aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/asn1/doc/src/asn1ct.xml9
-rw-r--r--lib/asn1/src/Makefile4
-rw-r--r--lib/asn1/src/asn1ct_check.erl105
-rw-r--r--lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl3
-rw-r--r--lib/asn1/src/asn1ct_constructed_per.erl71
-rw-r--r--lib/asn1/src/asn1ct_gen.erl203
-rw-r--r--lib/asn1/src/asn1ct_imm.erl44
-rw-r--r--lib/asn1/src/asn1ct_parser2.erl8
-rw-r--r--lib/asn1/src/asn1ct_value.erl17
-rw-r--r--lib/asn1/src/asn1rtt_check.erl91
-rw-r--r--lib/asn1/src/asn1rtt_per_common.erl41
-rw-r--r--lib/asn1/src/prepare_templates.erl72
-rw-r--r--lib/asn1/test/Makefile13
-rw-r--r--lib/asn1/test/asn1_SUITE.erl408
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Constraints.py5
-rw-r--r--lib/asn1/test/asn1_SUITE_data/Default.asn3
-rw-r--r--lib/asn1/test/asn1_SUITE_data/PrimStrings.asn18
-rw-r--r--lib/asn1/test/asn1_SUITE_data/UPERDefault.asn18
-rw-r--r--lib/asn1/test/asn1_test_lib.erl179
-rw-r--r--lib/asn1/test/asn1_wrapper.erl49
-rw-r--r--lib/asn1/test/ber_decode_error.erl10
-rw-r--r--lib/asn1/test/choice_extension.erl37
-rw-r--r--lib/asn1/test/h323test.erl86
-rw-r--r--lib/asn1/test/pem_performance.erl37
-rw-r--r--lib/asn1/test/testChoExtension.erl9
-rw-r--r--lib/asn1/test/testChoExternal.erl18
-rw-r--r--lib/asn1/test/testChoOptional.erl99
-rw-r--r--lib/asn1/test/testChoOptionalImplicitTag.erl101
-rw-r--r--lib/asn1/test/testChoPrim.erl106
-rw-r--r--lib/asn1/test/testChoRecursive.erl4
-rw-r--r--lib/asn1/test/testChoTypeRefCho.erl50
-rw-r--r--lib/asn1/test/testChoTypeRefPrim.erl72
-rw-r--r--lib/asn1/test/testChoTypeRefSeq.erl91
-rw-r--r--lib/asn1/test/testChoTypeRefSet.erl92
-rw-r--r--lib/asn1/test/testChoiceIndefinite.erl4
-rw-r--r--lib/asn1/test/testConstraints.erl77
-rw-r--r--lib/asn1/test/testContextSwitchingTypes.erl42
-rw-r--r--lib/asn1/test/testDER.erl34
-rw-r--r--lib/asn1/test/testDeepTConstr.erl4
-rw-r--r--lib/asn1/test/testDef.erl118
-rw-r--r--lib/asn1/test/testDoubleEllipses.erl84
-rw-r--r--lib/asn1/test/testEnumExt.erl12
-rw-r--r--lib/asn1/test/testFragmented.erl4
-rw-r--r--lib/asn1/test/testINSTANCE_OF.erl43
-rw-r--r--lib/asn1/test/testInfObj.erl4
-rw-r--r--lib/asn1/test/testInfObjectClass.erl24
-rw-r--r--lib/asn1/test/testMegaco.erl161
-rw-r--r--lib/asn1/test/testMergeCompile.erl114
-rw-r--r--lib/asn1/test/testNBAPsystem.erl25
-rw-r--r--lib/asn1/test/testOpenTypeImplicitTag.erl19
-rw-r--r--lib/asn1/test/testOpt.erl111
-rw-r--r--lib/asn1/test/testParamBasic.erl64
-rw-r--r--lib/asn1/test/testParameterizedInfObj.erl69
-rw-r--r--lib/asn1/test/testPrim.erl132
-rw-r--r--lib/asn1/test/testPrimExternal.erl105
-rw-r--r--lib/asn1/test/testPrimStrings.erl49
-rw-r--r--lib/asn1/test/testSelectionTypes.erl15
-rw-r--r--lib/asn1/test/testSeq2738.erl19
-rw-r--r--lib/asn1/test/testSeqDefault.erl198
-rw-r--r--lib/asn1/test/testSeqExtension.erl8
-rw-r--r--lib/asn1/test/testSeqExternal.erl131
-rw-r--r--lib/asn1/test/testSeqIndefinite.erl48
-rw-r--r--lib/asn1/test/testSeqOf.erl12
-rw-r--r--lib/asn1/test/testSeqOfCho.erl150
-rw-r--r--lib/asn1/test/testSeqOfExternal.erl188
-rw-r--r--lib/asn1/test/testSeqOfIndefinite.erl78
-rw-r--r--lib/asn1/test/testSeqOfTag.erl185
-rw-r--r--lib/asn1/test/testSeqOptional.erl199
-rw-r--r--lib/asn1/test/testSeqPrim.erl63
-rw-r--r--lib/asn1/test/testSeqSetDefaultVal.erl609
-rw-r--r--lib/asn1/test/testSeqSetIndefinite.erl52
-rw-r--r--lib/asn1/test/testSeqTag.erl86
-rw-r--r--lib/asn1/test/testSeqTypeRefCho.erl21
-rw-r--r--lib/asn1/test/testSeqTypeRefPrim.erl42
-rw-r--r--lib/asn1/test/testSeqTypeRefSeq.erl166
-rw-r--r--lib/asn1/test/testSeqTypeRefSet.erl45
-rw-r--r--lib/asn1/test/testSetDefault.erl76
-rw-r--r--lib/asn1/test/testSetExtension.erl85
-rw-r--r--lib/asn1/test/testSetExternal.erl119
-rw-r--r--lib/asn1/test/testSetIndefinite.erl41
-rw-r--r--lib/asn1/test/testSetOf.erl282
-rw-r--r--lib/asn1/test/testSetOfCho.erl150
-rw-r--r--lib/asn1/test/testSetOfExternal.erl151
-rw-r--r--lib/asn1/test/testSetOfTag.erl185
-rw-r--r--lib/asn1/test/testSetOptional.erl4
-rw-r--r--lib/asn1/test/testSetPrim.erl66
-rw-r--r--lib/asn1/test/testSetTag.erl87
-rw-r--r--lib/asn1/test/testSetTypeRefCho.erl21
-rw-r--r--lib/asn1/test/testSetTypeRefPrim.erl30
-rw-r--r--lib/asn1/test/testSetTypeRefSeq.erl20
-rw-r--r--lib/asn1/test/testSetTypeRefSet.erl163
-rw-r--r--lib/asn1/test/testTCAP.erl52
-rw-r--r--lib/asn1/test/testTimer.erl21
-rw-r--r--lib/asn1/test/testTypeValueNotation.erl22
-rw-r--r--lib/asn1/test/testWSParamClass.erl5
-rw-r--r--lib/asn1/test/testX420.erl24
-rw-r--r--lib/asn1/test/test_driver_load.erl45
-rw-r--r--lib/asn1/test/test_modified_x420.erl5
-rw-r--r--lib/asn1/test/test_partial_incomplete_decode.erl116
-rw-r--r--lib/asn1/test/test_selective_decode.erl45
-rw-r--r--lib/asn1/test/test_special_decode_performance.erl6
-rw-r--r--lib/asn1/test/test_undecoded_rest.erl52
-rw-r--r--lib/asn1/test/test_x691.erl183
-rw-r--r--lib/common_test/src/cth_log_redirect.erl12
-rw-r--r--lib/common_test/test/common_test.cover1
-rw-r--r--lib/common_test/test/ct_pre_post_test_io_SUITE.erl43
-rw-r--r--lib/common_test/test/ct_pre_post_test_io_SUITE_data/cth_ctrl.erl3
-rw-r--r--lib/compiler/src/beam_clean.erl2
-rw-r--r--lib/compiler/src/beam_type.erl2
-rw-r--r--lib/compiler/src/beam_validator.erl2
-rw-r--r--lib/compiler/src/compile.erl4
-rw-r--r--lib/compiler/src/core_scan.erl4
-rw-r--r--lib/compiler/src/v3_core.erl2
-rw-r--r--lib/compiler/src/v3_kernel.erl8
-rw-r--r--lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/lists1.erl4
-rw-r--r--lib/debugger/test/int_SUITE_data/lists1.erl4
-rw-r--r--lib/debugger/test/int_SUITE_data/my_lists.erl16
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_clean.erl2
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_type.erl2
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/compile.erl4
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/core_scan.erl4
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/sys_pre_expand.erl4
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/v3_core.erl2
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/src/compiler/v3_kernel.erl6
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_cgi.erl2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/trec12
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/appmon_place.erl2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/contract3.erl11
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/empty_list_infimum.erl6
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/gencall.erl2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/maybe_improper.erl17
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/overloaded1.erl10
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/trec.erl16
-rw-r--r--lib/diameter/doc/src/notes.xml30
-rw-r--r--lib/diameter/src/base/diameter_codec.erl20
-rw-r--r--lib/diameter/src/base/diameter_types.erl21
-rw-r--r--lib/diameter/src/base/diameter_watchdog.erl26
-rw-r--r--lib/diameter/src/diameter.appup.src10
-rw-r--r--lib/diameter/vsn.mk2
-rw-r--r--lib/eldap/doc/src/eldap.xml33
-rw-r--r--lib/eldap/src/eldap.erl89
-rw-r--r--lib/eldap/test/README36
-rw-r--r--lib/eldap/test/eldap.cfg1
-rw-r--r--lib/eldap/test/eldap_basic_SUITE.erl174
-rw-r--r--lib/eldap/test/eldap_basic_SUITE_data/certs/README1
-rw-r--r--lib/eldap/test/ldap_server/slapd.conf30
-rw-r--r--lib/eldap/test/make_certs.erl313
-rw-r--r--lib/erl_docgen/priv/css/otp_doc.css123
-rw-r--r--lib/erl_docgen/priv/js/flipmenu/Makefile3
-rw-r--r--lib/erl_docgen/priv/js/flipmenu/flipmenu.js17
-rw-r--r--lib/erl_docgen/priv/js/flipmenu/jquery-2.0.3.min.js6
-rw-r--r--lib/erl_docgen/priv/xsl/db_html.xsl45
-rw-r--r--lib/erl_interface/src/legacy/erl_eterm.c2
-rw-r--r--lib/erl_interface/test/all_SUITE_data/ei_runner.c4
-rw-r--r--lib/erl_interface/test/all_SUITE_data/runner.c4
-rw-r--r--lib/erl_interface/test/ei_accept_SUITE.erl2
-rw-r--r--lib/erl_interface/test/erl_connect_SUITE.erl2
-rw-r--r--lib/erl_interface/test/erl_eterm_SUITE.erl10
-rw-r--r--lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c8
-rw-r--r--lib/eunit/src/eunit_proc.erl13
-rw-r--r--lib/eunit/src/eunit_surefire.erl2
-rw-r--r--lib/hipe/cerl/erl_types.erl13
-rw-r--r--lib/ic/c_src/Makefile.in6
-rw-r--r--lib/inets/doc/src/httpc.xml7
-rw-r--r--lib/inets/src/http_client/httpc.erl23
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl69
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl6
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl128
-rw-r--r--lib/inets/src/http_server/httpd_conf.erl2
-rw-r--r--lib/inets/src/http_server/httpd_log.erl15
-rw-r--r--lib/inets/src/http_server/httpd_request_handler.erl11
-rw-r--r--lib/inets/src/http_server/httpd_response.erl33
-rw-r--r--lib/inets/src/http_server/mod_cgi.erl10
-rw-r--r--lib/inets/src/http_server/mod_head.erl4
-rw-r--r--lib/inets/src/inets_app/inets_internal.hrl2
-rw-r--r--lib/inets/test/httpc_SUITE.erl17
-rw-r--r--lib/inets/test/httpd_basic_SUITE.erl89
-rw-r--r--lib/inets/test/httpd_basic_SUITE_data/Makefile.src14
-rw-r--r--lib/inets/test/httpd_basic_SUITE_data/cgi_sleep.c26
-rw-r--r--lib/kernel/doc/src/gen_sctp.xml2
-rw-r--r--lib/kernel/doc/src/rpc.xml2
-rw-r--r--lib/kernel/src/gen_sctp.erl4
-rw-r--r--lib/kernel/src/inet.erl15
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/observer/doc/src/ttb.xml7
-rw-r--r--lib/orber/test/multi_ORB_SUITE.erl47
-rw-r--r--lib/orber/test/orber_nat_SUITE.erl107
-rw-r--r--lib/os_mon/src/memsup.erl19
-rw-r--r--lib/public_key/asn1/OTP-PKIX.asn112
-rw-r--r--lib/public_key/doc/src/using_public_key.xml6
-rw-r--r--lib/public_key/src/pubkey_cert_records.erl11
-rw-r--r--lib/public_key/test/public_key_SUITE.erl38
-rw-r--r--lib/sasl/src/sasl.erl4
-rw-r--r--lib/ssh/doc/src/ssh.xml44
-rw-r--r--lib/ssh/doc/src/ssh_client_key_api.xml6
-rw-r--r--lib/ssh/doc/src/ssh_server_key_api.xml14
-rw-r--r--lib/ssh/src/Makefile3
-rw-r--r--lib/ssh/src/ssh.app.src3
-rw-r--r--lib/ssh/src/ssh.erl153
-rw-r--r--lib/ssh/src/ssh.hrl4
-rw-r--r--lib/ssh/src/ssh_acceptor.erl19
-rw-r--r--lib/ssh/src/ssh_auth.erl99
-rw-r--r--lib/ssh/src/ssh_bits.erl334
-rw-r--r--lib/ssh/src/ssh_channel.erl2
-rw-r--r--lib/ssh/src/ssh_channel_sup.erl4
-rw-r--r--lib/ssh/src/ssh_cli.erl110
-rw-r--r--lib/ssh/src/ssh_connect.hrl5
-rw-r--r--lib/ssh/src/ssh_connection.erl652
-rw-r--r--lib/ssh/src/ssh_connection_controler.erl137
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl1280
-rw-r--r--lib/ssh/src/ssh_connection_manager.erl916
-rw-r--r--lib/ssh/src/ssh_connection_sup.erl87
-rw-r--r--lib/ssh/src/ssh_message.erl529
-rw-r--r--lib/ssh/src/ssh_no_io.erl23
-rw-r--r--lib/ssh/src/ssh_sftpd.erl2
-rw-r--r--lib/ssh/src/ssh_subsystem_sup.erl16
-rw-r--r--lib/ssh/src/ssh_sup.erl15
-rw-r--r--lib/ssh/src/ssh_system_sup.erl19
-rw-r--r--lib/ssh/src/ssh_transport.erl203
-rw-r--r--lib/ssh/src/ssh_userreg.erl141
-rw-r--r--lib/ssh/src/ssh_xfer.erl4
-rw-r--r--lib/ssh/src/sshc_sup.erl6
-rw-r--r--lib/ssh/test/Makefile6
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl110
-rw-r--r--lib/ssh/test/ssh_connection_SUITE.erl33
-rw-r--r--lib/ssh/test/ssh_peername_sockname_server.erl54
-rw-r--r--lib/ssh/test/ssh_test_cli.erl81
-rw-r--r--lib/ssl/doc/src/ssl.xml19
-rw-r--r--lib/ssl/src/dtls_handshake.erl2
-rw-r--r--lib/ssl/src/inet_tls_dist.erl5
-rw-r--r--lib/ssl/src/ssl_cipher.erl2
-rw-r--r--lib/ssl/src/ssl_handshake.erl115
-rw-r--r--lib/ssl/src/ssl_handshake.hrl22
-rw-r--r--lib/ssl/src/ssl_internal.hrl3
-rw-r--r--lib/ssl/src/tls.erl9
-rw-r--r--lib/ssl/src/tls_connection.erl31
-rw-r--r--lib/ssl/src/tls_handshake.erl11
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl12
-rw-r--r--lib/stdlib/doc/src/re.xml6
-rw-r--r--lib/stdlib/src/dict.erl2
-rw-r--r--lib/stdlib/src/erl_eval.erl4
-rw-r--r--lib/stdlib/src/erl_tar.erl4
-rw-r--r--lib/stdlib/src/filelib.erl4
-rw-r--r--lib/stdlib/src/gen_server.erl2
-rw-r--r--lib/stdlib/src/io_lib.erl2
-rw-r--r--lib/stdlib/src/lists.erl4
-rw-r--r--lib/stdlib/src/math.erl6
-rw-r--r--lib/stdlib/src/string.erl4
-rw-r--r--lib/stdlib/test/binary_module_SUITE.erl4
-rw-r--r--lib/stdlib/test/slave_SUITE.erl2
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/test_server/src/ts.erl2
-rw-r--r--lib/tools/emacs/erlang-eunit.el4
-rw-r--r--lib/tools/emacs/erlang-start.el2
-rw-r--r--lib/tools/emacs/erlang.el40
-rw-r--r--lib/tools/src/cover.erl44
-rw-r--r--lib/tools/src/tags.erl4
-rw-r--r--lib/tools/test/cover_SUITE.erl37
-rw-r--r--lib/tools/test/cover_SUITE_data/otp_11439/t.erl11
-rw-r--r--lib/tools/test/eprof_SUITE_data/eed.erl8
-rw-r--r--lib/xmerl/src/xmerl.erl25
-rw-r--r--lib/xmerl/src/xmerl_regexp.erl12
-rw-r--r--lib/xmerl/src/xmerl_xpath.erl51
-rw-r--r--lib/xmerl/test/xmerl_SUITE.erl7
-rw-r--r--lib/xmerl/test/xmerl_SUITE_data/xpath/purchaseOrder.xml5
-rw-r--r--lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl31
266 files changed, 6683 insertions, 8811 deletions
diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml
index 23d122f69a..fcd77e9dc6 100644
--- a/lib/asn1/doc/src/asn1ct.xml
+++ b/lib/asn1/doc/src/asn1ct.xml
@@ -66,7 +66,7 @@
<v>Option = ber | per | uper | der | compact_bit_string |
legacy_bit_string |
noobj | {n2n, EnumTypeName} |{outdir, Dir} | {i, IncludeDir} |
- asn1config | undec_rest |
+ asn1config | undec_rest | no_ok_wrapper |
{macro_name_prefix, Prefix} | {record_name_prefix, Prefix} | verbose | warnings_as_errors</v>
<v>OldOption = ber | per</v>
<v>Reason = term()</v>
@@ -238,6 +238,13 @@ File3.asn </pre>
list or a binary. Earlier versions of the compiler ignored
those following bytes.</p>
</item>
+ <tag><c>no_ok_wrapper</c></tag>
+ <item>
+ <p>If this option is given, the generated <c>encode/2</c>
+ and <c>decode/2</c> functions will not wrap a successful
+ return value in an <c>{ok,...}</c> tuple. If any error
+ occurs, there will be an exception.</p>
+ </item>
<tag><c>{macro_name_prefix, Prefix}</c></tag>
<item>
<p>All macro names generated by the compiler are prefixed with
diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile
index 3f24e15c04..500f4a1358 100644
--- a/lib/asn1/src/Makefile
+++ b/lib/asn1/src/Makefile
@@ -135,7 +135,7 @@ $(EBIN)/asn1ct_func.$(EMULATOR): asn1ct_func.erl
asn1ct_eval_%.erl: asn1ct_eval_%.funcs
$(gen_verbose)erl -pa $(EBIN) -noshell -noinput \
- -run prepare_templates gen_asn1ct_eval $< >$@
+ -run prepare_templates gen_asn1ct_eval $<
$(APP_TARGET): $(APP_SRC) ../vsn.mk
$(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
@@ -180,7 +180,7 @@ RT_TEMPLATES_TARGET = $(RT_TEMPLATES:%=%.$(EMULATOR))
asn1ct_rtt.erl: prepare_templates.$(EMULATOR) $(RT_TEMPLATES_TARGET)
$(gen_verbose)erl -noshell -noinput -run prepare_templates gen_asn1ct_rtt \
- $(RT_TEMPLATES_TARGET) >asn1ct_rtt.erl
+ $(RT_TEMPLATES_TARGET)
prepare_templates.$(EMULATOR): prepare_templates.erl
$(V_ERLC) prepare_templates.erl
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index eddcda0018..04227fd23b 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -2534,89 +2534,54 @@ normalize_integer(S,Int=#'Externalvaluereference'{value=Name},Type) ->
normalize_integer(_,Int,_) ->
exit({'Unknown INTEGER value',Int}).
-normalize_bitstring(S,Value,Type)->
- %% There are four different Erlang formats of BIT STRING:
- %% 1 - a list of ones and zeros.
- %% 2 - a list of atoms.
- %% 3 - as an integer, for instance in hexadecimal form.
- %% 4 - as a tuple {Unused, Binary} where Unused is an integer
- %% and tells how many bits of Binary are unused.
- %%
- %% normalize_bitstring/3 transforms Value according to:
- %% A to 3,
- %% B to 1,
- %% C to 1 or 3
- %% D to 2,
- %% Value can be on format:
- %% A - {hstring, String}, where String is a hexadecimal string.
- %% B - {bstring, String}, where String is a string on bit format
- %% C - #'Externalvaluereference'{value=V}, where V is a defined value
- %% D - list of #'Externalvaluereference', where each value component
- %% is an identifier corresponing to NamedBits in Type.
- %% E - list of ones and zeros, if Value already is normalized.
+%% normalize_bitstring(S, Value, Type) -> bitstring()
+%% Convert a literal value for a BIT STRING to an Erlang bit string.
+%%
+normalize_bitstring(S, Value, Type)->
case Value of
{hstring,String} when is_list(String) ->
- hstring_to_int(String);
+ hstring_to_bitstring(String);
{bstring,String} when is_list(String) ->
- bstring_to_bitlist(String);
- Rec when is_record(Rec,'Externalvaluereference') ->
- get_normalized_value(S,Value,Type,
- fun normalize_bitstring/3,[]);
+ bstring_to_bitstring(String);
+ #'Externalvaluereference'{} ->
+ get_normalized_value(S, Value, Type,
+ fun normalize_bitstring/3, []);
RecList when is_list(RecList) ->
- case Type of
- NBL when is_list(NBL) ->
- F = fun(#'Externalvaluereference'{value=Name}) ->
- case lists:keysearch(Name,1,NBL) of
- {value,{Name,_}} ->
- Name;
- Other ->
- throw({error,Other})
- end;
- (I) when I =:= 1; I =:= 0 ->
- I;
- (Other) ->
- throw({error,Other})
- end,
- case catch lists:map(F,RecList) of
- {error,Reason} ->
- asn1ct:warning("default value not "
- "compatible with type definition ~p~n",
- [Reason],S,
- "default value not "
- "compatible with type definition"),
- Value;
- NewList ->
- NewList
- end;
- _ ->
+ F = fun(#'Externalvaluereference'{value=Name}) ->
+ case lists:keymember(Name, 1, Type) of
+ true -> Name;
+ false -> throw({error,false})
+ end;
+ (Name) when is_atom(Name) ->
+ %% Already normalized.
+ Name;
+ (Other) ->
+ throw({error,Other})
+ end,
+ try
+ lists:map(F, RecList)
+ catch
+ throw:{error,Reason} ->
asn1ct:warning("default value not "
"compatible with type definition ~p~n",
- [RecList],S,
+ [Reason],S,
"default value not "
"compatible with type definition"),
Value
end;
- {Name,String} when is_atom(Name) ->
- normalize_bitstring(S,String,Type);
- Other ->
- asn1ct:warning("illegal default value ~p~n",[Other],S,
- "illegal default value"),
- Value
+ Bs when is_bitstring(Bs) ->
+ %% Already normalized.
+ Bs
end.
-hstring_to_int(L) when is_list(L) ->
- hstring_to_int(L,0).
-hstring_to_int([H|T],Acc) when H >= $A, H =< $F ->
- hstring_to_int(T,(Acc bsl 4) + (H - $A + 10) ) ;
-hstring_to_int([H|T],Acc) when H >= $0, H =< $9 ->
- hstring_to_int(T,(Acc bsl 4) + (H - $0));
-hstring_to_int([],Acc) ->
- Acc.
+hstring_to_bitstring(L) ->
+ << <<(hex_to_int(D)):4>> || D <- L >>.
-bstring_to_bitlist([H|T]) when H == $0; H == $1 ->
- [H - $0 | bstring_to_bitlist(T)];
-bstring_to_bitlist([]) ->
- [].
+bstring_to_bitstring(L) ->
+ << <<(D-$0):1>> || D <- L >>.
+
+hex_to_int(D) when $0 =< D, D =< $9 -> D - $0;
+hex_to_int(D) when $A =< D, D =< $F -> D - ($A - 10).
%% normalize_octetstring/1 changes representation of input Value to a
%% list of octets.
diff --git a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
index 8359b81b33..a38da8bcc2 100644
--- a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
@@ -1155,7 +1155,8 @@ gen_dec_line(Erules,TopType,Cname,CTags,Type,OptOrMand,DecObjInf) ->
emit([indent(4),"_ ->",nl]),
case OptOrMand of
- {'DEFAULT', Def} ->
+ {'DEFAULT', Def0} ->
+ Def = asn1ct_gen:conform_value(Type, Def0),
emit([indent(8),"{",{asis,Def},",",{prev,tlv},"}",nl]);
'OPTIONAL' ->
emit([indent(8),"{ asn1_NOVALUE, ",{prev,tlv},"}",nl])
diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl
index 8d4afc0a0b..4672f7edd3 100644
--- a/lib/asn1/src/asn1ct_constructed_per.erl
+++ b/lib/asn1/src/asn1ct_constructed_per.erl
@@ -770,8 +770,10 @@ optionals(L) -> optionals(L,[],2).
optionals([#'ComponentType'{prop='OPTIONAL'}|Rest], Acc, Pos) ->
optionals(Rest, [Pos|Acc], Pos+1);
-optionals([#'ComponentType'{prop={'DEFAULT',Val}}|Rest], Acc, Pos) ->
- optionals(Rest, [{Pos,Val}|Acc], Pos+1);
+optionals([#'ComponentType'{typespec=T,prop={'DEFAULT',Val}}|Rest],
+ Acc, Pos) ->
+ Vals = def_values(T, Val),
+ optionals(Rest, [{Pos,Vals}|Acc], Pos+1);
optionals([#'ComponentType'{}|Rest], Acc, Pos) ->
optionals(Rest, Acc, Pos+1);
optionals([], Acc, _) ->
@@ -888,7 +890,8 @@ gen_enc_components_call1(Erule,TopType,
optional ->
asn1ct_imm:enc_absent(Element, [asn1_NOVALUE], Imm1);
{default,Def} ->
- asn1ct_imm:enc_absent(Element, [asn1_DEFAULT,Def], Imm1)
+ DefValues = def_values(Type, Def),
+ asn1ct_imm:enc_absent(Element, DefValues, Imm1)
end,
Imm = case Imm2 of
[] -> [];
@@ -899,6 +902,38 @@ gen_enc_components_call1(_Erule,_TopType,[],Pos,_,_, Acc) ->
ImmList = lists:reverse(Acc),
{ImmList,Pos}.
+def_values(#type{def=#'Externaltypereference'{module=Mod,type=Type}}, Def) ->
+ #typedef{typespec=T} = asn1_db:dbget(Mod, Type),
+ def_values(T, Def);
+def_values(#type{def={'BIT STRING',[]}}, Bs) when is_bitstring(Bs) ->
+ ListBs = [B || <<B:1>> <= Bs],
+ IntBs = lists:foldl(fun(B, A) ->
+ (A bsl 1) bor B
+ end, 0, lists:reverse(ListBs)),
+ Sz = bit_size(Bs),
+ Compact = case 8 - Sz rem 8 of
+ 8 ->
+ {0,Bs};
+ Unused ->
+ {Unused,<<Bs:Sz/bits,0:Unused>>}
+ end,
+ [asn1_DEFAULT,Bs,Compact,ListBs,IntBs];
+def_values(#type{def={'BIT STRING',[_|_]=Ns}}, List) when is_list(List) ->
+ Bs = asn1ct_gen:named_bitstring_value(List, Ns),
+ ListBs = [B || <<B:1>> <= Bs],
+ IntBs = lists:foldl(fun(B, A) ->
+ (A bsl 1) bor B
+ end, 0, lists:reverse(ListBs)),
+ Args = [List,Bs,ListBs,IntBs],
+ {call,per_common,is_default_bitstring,Args};
+def_values(#type{def={'INTEGER',Ns}}, Def) ->
+ [asn1_DEFAULT,Def|case lists:keyfind(Def, 2, Ns) of
+ false -> [];
+ {Val,Def} -> [Val]
+ end];
+def_values(_, Def) ->
+ [asn1_DEFAULT,Def].
+
gen_enc_line_imm(Erule, TopType, Cname, Type, Element, DynamicEnc, Ext) ->
Imm0 = gen_enc_line_imm_1(Erule, TopType, Cname, Type,
Element, DynamicEnc),
@@ -1207,7 +1242,8 @@ gen_dec_comp_call(Comp, Erule, TopType, Tpos, OptTable, DecInfObj,
comp_call_pre_post(noext, mandatory, _, _, _, _, _, _) ->
{[],[]};
-comp_call_pre_post(noext, Prop, _, _, TextPos, OptTable, NumOptionals, Ext) ->
+comp_call_pre_post(noext, Prop, _, Type, TextPos,
+ OptTable, NumOptionals, Ext) ->
%% OPTIONAL or DEFAULT
OptPos = get_optionality_pos(TextPos, OptTable),
Element = case NumOptionals - OptPos of
@@ -1225,7 +1261,7 @@ comp_call_pre_post(noext, Prop, _, _, TextPos, OptTable, NumOptionals, Ext) ->
emit([";",nl,
"0 ->",nl,
"{"]),
- gen_dec_component_no_val(Ext, Prop),
+ gen_dec_component_no_val(Ext, Type, Prop),
emit([",",{curr,bytes},"}",nl,
"end"]),
St
@@ -1247,10 +1283,10 @@ comp_call_pre_post({ext,_,_}, Prop, Pos, Type, _, _, _, Ext) ->
components=ExtGroupCompList2}}
when is_integer(Number2)->
emit("{extAddGroup,"),
- gen_dec_extaddGroup_no_val(Ext, ExtGroupCompList2),
+ gen_dec_extaddGroup_no_val(Ext, Type, ExtGroupCompList2),
emit("}");
_ ->
- gen_dec_component_no_val(Ext, Prop)
+ gen_dec_component_no_val(Ext, Type, Prop)
end,
emit([",",{curr,bytes},"}",nl,
"end"]),
@@ -1265,21 +1301,22 @@ is_mandatory_predef_tab_c(_, _, {"got objfun through args","ObjFun"}) ->
is_mandatory_predef_tab_c(_,_,_) ->
true.
-gen_dec_extaddGroup_no_val(Ext,[#'ComponentType'{prop=Prop}])->
- gen_dec_component_no_val(Ext,Prop),
+gen_dec_extaddGroup_no_val(Ext, Type, [#'ComponentType'{prop=Prop}])->
+ gen_dec_component_no_val(Ext, Type, Prop),
ok;
-gen_dec_extaddGroup_no_val(Ext,[#'ComponentType'{prop=Prop}|Rest])->
- gen_dec_component_no_val(Ext,Prop),
- emit({","}),
- gen_dec_extaddGroup_no_val(Ext,Rest);
-gen_dec_extaddGroup_no_val(_, []) ->
+gen_dec_extaddGroup_no_val(Ext, Type, [#'ComponentType'{prop=Prop}|Rest])->
+ gen_dec_component_no_val(Ext, Type, Prop),
+ emit(","),
+ gen_dec_extaddGroup_no_val(Ext, Type, Rest);
+gen_dec_extaddGroup_no_val(_, _, []) ->
ok.
-gen_dec_component_no_val(_,{'DEFAULT',DefVal}) ->
+gen_dec_component_no_val(_, Type, {'DEFAULT',DefVal0}) ->
+ DefVal = asn1ct_gen:conform_value(Type, DefVal0),
emit([{asis,DefVal}]);
-gen_dec_component_no_val(_,'OPTIONAL') ->
+gen_dec_component_no_val(_, _, 'OPTIONAL') ->
emit({"asn1_NOVALUE"});
-gen_dec_component_no_val({ext,_,_},mandatory) ->
+gen_dec_component_no_val({ext,_,_}, _, mandatory) ->
emit({"asn1_NOVALUE"}).
diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl
index e6ec0cb12b..30d337635b 100644
--- a/lib/asn1/src/asn1ct_gen.erl
+++ b/lib/asn1/src/asn1ct_gen.erl
@@ -33,7 +33,9 @@
insert_once/2,
ct_gen_module/1,
index2suffix/1,
- get_record_name_prefix/0]).
+ get_record_name_prefix/0,
+ conform_value/2,
+ named_bitstring_value/2]).
-export([pgen/5,
mk_var/1,
un_hyphen_var/1]).
@@ -85,6 +87,8 @@ pgen_module(OutFile,Erules,Module,
"%%%",nl]),
asn1ct_func:generate(Fid),
file:close(Fid),
+ _ = erase(gen_file_out),
+ _ = erase(outfile),
asn1ct:verbose("--~p--~n",[{generated,ErlFile}],Options).
@@ -907,49 +911,45 @@ pgen_dispatcher(Erules,_Module,{[],_Values,_,_,_Objects,_ObjectSets}) ->
pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
emit(["-export([encode/2,decode/2]).",nl,nl]),
gen_info_functions(Erules),
- NoFinalPadding = lists:member(no_final_padding,get(encoding_options)),
- {Call,BytesAsBinary} =
- case Erules of
- per ->
- asn1ct_func:need({Erules,complete,1}),
- {["complete(encode_disp(Type, Data))"],"Bytes"};
- ber ->
- {"encode_disp(Type,Data)","iolist_to_binary(Bytes)"};
- uper when NoFinalPadding == true ->
- asn1ct_func:need({Erules,complete_NFP,1}),
- {"complete_NFP(encode_disp(Type, Data))","Bytes"};
- uper ->
- asn1ct_func:need({Erules,complete,1}),
- {["complete(encode_disp(Type, Data))"],"Bytes"}
- end,
- emit(["encode(Type,Data) ->",nl,
- "try ",Call," of",nl,
- case erule(Erules) of
- ber ->
- [" {Bytes,_Len} ->",nl,
- " {ok,",BytesAsBinary,"}",nl];
- per ->
- [" Bytes ->",nl,
- " {ok,",BytesAsBinary,"}",nl]
- end,
- " catch",nl,
- " Class:Exception when Class =:= error; Class =:= exit ->",nl,
- " case Exception of",nl,
- " {error,Reason}=Error ->",nl,
- " Error;",nl,
- " Reason ->",nl,
- " {error,{asn1,Reason}}",nl,
- " end",nl,
- "end.",nl,nl]),
-
- Return_rest = lists:member(undec_rest,get(encoding_options)),
+
+ Options = get(encoding_options),
+ NoFinalPadding = lists:member(no_final_padding, Options),
+ NoOkWrapper = proplists:get_bool(no_ok_wrapper, Options),
+
+ Call = case Erules of
+ per ->
+ asn1ct_func:need({Erules,complete,1}),
+ "complete(encode_disp(Type, Data))";
+ ber ->
+ "iolist_to_binary(element(1, encode_disp(Type, Data)))";
+ uper when NoFinalPadding == true ->
+ asn1ct_func:need({Erules,complete_NFP,1}),
+ "complete_NFP(encode_disp(Type, Data))";
+ uper ->
+ asn1ct_func:need({Erules,complete,1}),
+ "complete(encode_disp(Type, Data))"
+ end,
+
+ emit(["encode(Type, Data) ->",nl]),
+ case NoOkWrapper of
+ true ->
+ emit([" ",Call,"."]);
+ false ->
+ emit(["try ",Call," of",nl,
+ " Bytes ->",nl,
+ " {ok,Bytes}",nl,
+ try_catch()])
+ end,
+ emit([nl,nl]),
+
+ Return_rest = proplists:get_bool(undec_rest, Options),
Data = case {Erules,Return_rest} of
{ber,true} -> "Data0";
_ -> "Data"
end,
emit(["decode(Type,",Data,") ->",nl]),
- DecAnonymous =
+ DecWrap =
case {Erules,Return_rest} of
{ber,false} ->
asn1ct_func:need({ber,ber_decode_nif,1}),
@@ -961,49 +961,26 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
_ ->
"Data"
end,
- DecWrap = case Erules of
- ber ->
- DecAnonymous;
- _ -> "Data"
- end,
-
- emit(["case catch decode_disp(Type,",DecWrap,") of",nl,
- " {'EXIT',{error,Reason}} ->",nl,
- " {error,Reason};",nl,
- " {'EXIT',Reason} ->",nl,
- " {error,{asn1,Reason}};",nl]),
- case {Erules,Return_rest} of
- {ber,false} ->
- emit([" Result ->",nl,
- " {ok,Result}",nl]);
- {ber,true} ->
- emit([" Result ->",nl,
- " {ok,Result,Rest}",nl]);
- {_,false} ->
- emit([" {X,_Rest} ->",nl,
- " {ok,X};",nl,
- " {X,_Rest,_Len} ->",nl,
- " {ok,X}",nl]);
- {per,true} ->
- emit([" {X,{_,Rest}} ->",nl,
- " {ok,X,Rest};",nl,
- " {X,{_,Rest},_Len} ->",nl,
- " {ok,X,Rest};",nl,
- " {X,Rest} ->",nl,
- " {ok,X,Rest};",nl,
- " {X,Rest,_Len} ->",nl,
- " {ok,X,Rest}",nl]);
- {uper,true} ->
- emit([" {X,{_,Rest}} ->",nl,
- " {ok,X,Rest};",nl,
- " {X,{_,Rest},_Len} ->",nl,
- " {ok,X,Rest};",nl,
- " {X,Rest} ->",nl,
- " {ok,X,Rest};",nl,
- " {X,Rest,_Len} ->",nl,
- " {ok,X,Rest}",nl])
+ emit([case NoOkWrapper of
+ false -> "try";
+ true -> "case"
+ end, " decode_disp(Type, ",DecWrap,") of",nl]),
+ case erule(Erules) of
+ ber ->
+ emit([" Result ->",nl]);
+ per ->
+ emit([" {Result,Rest} ->",nl])
+ end,
+ case Return_rest of
+ false -> result_line(NoOkWrapper, ["Result"]);
+ true -> result_line(NoOkWrapper, ["Result","Rest"])
+ end,
+ case NoOkWrapper of
+ false ->
+ emit([nl,try_catch(),nl,nl]);
+ true ->
+ emit([nl,"end.",nl,nl])
end,
- emit(["end.",nl,nl]),
gen_decode_partial_incomplete(Erules),
@@ -1016,8 +993,30 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
gen_dispatcher(Types,"encode_disp","enc_",""),
gen_dispatcher(Types,"decode_disp","dec_","")
end,
- emit([nl]),
- emit({nl,nl}).
+ emit([nl,nl]).
+
+result_line(NoOkWrapper, Items) ->
+ S = [" "|case NoOkWrapper of
+ false -> result_line_1(["ok"|Items]);
+ true -> result_line_1(Items)
+ end],
+ emit(lists:flatten(S)).
+
+result_line_1([SingleItem]) ->
+ SingleItem;
+result_line_1(Items) ->
+ ["{",string:join(Items, ","),"}"].
+
+try_catch() ->
+ [" catch",nl,
+ " Class:Exception when Class =:= error; Class =:= exit ->",nl,
+ " case Exception of",nl,
+ " {error,Reason}=Error ->",nl,
+ " Error;",nl,
+ " Reason ->",nl,
+ " {error,{asn1,Reason}}",nl,
+ " end",nl,
+ "end."].
gen_info_functions(Erules) ->
emit(["encoding_rule() -> ",
@@ -1488,8 +1487,14 @@ gen_prim_check_call(PrimType, Default, Element, Type) ->
end,
check_call(check_int, [Default,Element,{asis,NNL}]);
'BIT STRING' ->
- {_,NBL} = Type#type.def,
- check_call(check_bitstring, [Default,Element,{asis,NBL}]);
+ case Type#type.def of
+ {_,[]} ->
+ check_call(check_bitstring,
+ [Default,Element]);
+ {_,[_|_]=NBL} ->
+ check_call(check_named_bitstring,
+ [Default,Element,{asis,NBL}])
+ end;
'OCTET STRING' ->
check_call(check_octetstring, [Default,Element]);
'NULL' ->
@@ -1643,9 +1648,33 @@ unify_if_string(PrimType) ->
Other -> Other
end.
-
-
-
+conform_value(#type{def={'BIT STRING',[]}}, Bs) ->
+ case asn1ct:get_bit_string_format() of
+ compact when is_binary(Bs) ->
+ {0,Bs};
+ compact when is_bitstring(Bs) ->
+ Sz = bit_size(Bs),
+ Unused = 8 - bit_size(Bs),
+ {Unused,<<Bs:Sz/bits,0:Unused>>};
+ legacy ->
+ [B || <<B:1>> <= Bs];
+ bitstring when is_bitstring(Bs) ->
+ Bs
+ end;
+conform_value(_, Value) -> Value.
+
+named_bitstring_value(List, Names) ->
+ Int = lists:foldl(fun(N, A) ->
+ {N,Pos} = lists:keyfind(N, 1, Names),
+ A bor (1 bsl Pos)
+ end, 0, List),
+ named_bitstring_value_1(<<>>, Int).
+
+named_bitstring_value_1(Bs, 0) ->
+ Bs;
+named_bitstring_value_1(Bs, Int) ->
+ B = Int band 1,
+ named_bitstring_value_1(<<Bs/bitstring,B:1>>, Int bsr 1).
get_inner(A) when is_atom(A) -> A;
get_inner(Ext) when is_record(Ext,'Externaltypereference') -> Ext;
diff --git a/lib/asn1/src/asn1ct_imm.erl b/lib/asn1/src/asn1ct_imm.erl
index 892178f61b..20785cda8c 100644
--- a/lib/asn1/src/asn1ct_imm.erl
+++ b/lib/asn1/src/asn1ct_imm.erl
@@ -319,14 +319,22 @@ per_enc_extensions(Val0, Pos0, NumBits, Aligned) when NumBits > 0 ->
{'cond',[[{eq,Bitmap,0}],
['_'|Length ++ PutBits]],{var,"Extensions"}}].
-per_enc_optional(Val0, {Pos,Def}, _Aligned) when is_integer(Pos) ->
+per_enc_optional(Val0, {Pos,DefVals}, _Aligned) when is_integer(Pos),
+ is_list(DefVals) ->
Val1 = lists:concat(["element(",Pos,", ",Val0,")"]),
{B,[Val]} = mk_vars(Val1, []),
Zero = {put_bits,0,1,[1]},
One = {put_bits,1,1,[1]},
- B++[{'cond',[[{eq,Val,asn1_DEFAULT},Zero],
- [{eq,Val,Def},Zero],
- ['_',One]]}];
+ B++[{'cond',
+ [[{eq,Val,DefVal},Zero] || DefVal <- DefVals] ++ [['_',One]]}];
+per_enc_optional(Val0, {Pos,{call,M,F,A}}, _Aligned) when is_integer(Pos) ->
+ Val1 = lists:concat(["element(",Pos,", ",Val0,")"]),
+ {B,[Val,Tmp]} = mk_vars(Val1, [tmp]),
+ Zero = {put_bits,0,1,[1]},
+ One = {put_bits,1,1,[1]},
+ B++[{call,M,F,[Val|A],Tmp},
+ {'cond',
+ [[{eq,Tmp,true},Zero],['_',One]]}];
per_enc_optional(Val0, Pos, _Aligned) when is_integer(Pos) ->
Val1 = lists:concat(["element(",Pos,", ",Val0,")"]),
{B,[Val]} = mk_vars(Val1, []),
@@ -352,7 +360,12 @@ per_enc_sof(Val0, Constraint, ElementVar, ElementImm, Aligned) ->
PreBlock ++ EncLen ++ Lc
end.
-enc_absent(Val0, AbsVals, Body) ->
+enc_absent(Val0, {call,M,F,A}, Body) ->
+ {B,[Var,Tmp]} = mk_vars(Val0, [tmp]),
+ B++[{call,M,F,[Var|A],Tmp},
+ {'cond',
+ [[{eq,Tmp,true}],['_'|Body]]}];
+enc_absent(Val0, AbsVals, Body) when is_list(AbsVals) ->
{B,[Var]} = mk_vars(Val0, []),
Cs = [[{eq,Var,Aval}] || Aval <- AbsVals] ++ [['_'|Body]],
B++build_cond(Cs).
@@ -994,6 +1007,25 @@ mk_var(Base, V) ->
per_enc_integer_1(Val, [], Aligned) ->
[{'cond',[['_'|per_enc_unconstrained(Val, Aligned)]]}];
+per_enc_integer_1(Val, [{{'SingleValue',[_|_]=Svs}=Constr,[]}], Aligned) ->
+ %% An extensible constraint such as (1|17, ...).
+ %%
+ %% A subtle detail is that the extension root as described in the
+ %% ASN.1 spec should be used to determine whether a particular value
+ %% belongs to the extension root (as opposed to the effective
+ %% constraint, which will be used for the actual encoding).
+ %%
+ %% So for the example above, only the integers 1 and 17 should be
+ %% encoded as root values (extension bit = 0).
+
+ [{'ValueRange',{Lb,Ub}}] = effective_constraint(integer, [Constr]),
+ Root = [begin
+ {[],_,Put} = per_enc_constrained(Sv, Lb, Ub, Aligned),
+ [{eq,Val,Sv},{put_bits,0,1,[1]}|Put]
+ end || Sv <- Svs],
+ Cs = Root ++ [['_',{put_bits,1,1,[1]}|
+ per_enc_unconstrained(Val, Aligned)]],
+ build_cond(Cs);
per_enc_integer_1(Val0, [{{_,_}=Constr,[]}], Aligned) ->
{Prefix,Check,Action} = per_enc_integer_2(Val0, Constr, Aligned),
Prefix++build_cond([[Check,{put_bits,0,1,[1]}|Action],
@@ -1004,7 +1036,7 @@ per_enc_integer_1(Val0, [Constr], Aligned) ->
Prefix++build_cond([[Check|Action],
['_',{error,Val0}]]).
-per_enc_integer_2(Val, {'SingleValue',Sv}, Aligned) ->
+per_enc_integer_2(Val, {'SingleValue',Sv}, Aligned) when is_integer(Sv) ->
per_enc_constrained(Val, Sv, Sv, Aligned);
per_enc_integer_2(Val0, {'ValueRange',{Lb,'MAX'}}, Aligned)
when is_integer(Lb) ->
diff --git a/lib/asn1/src/asn1ct_parser2.erl b/lib/asn1/src/asn1ct_parser2.erl
index 1abccc8626..283616b157 100644
--- a/lib/asn1/src/asn1ct_parser2.erl
+++ b/lib/asn1/src/asn1ct_parser2.erl
@@ -38,6 +38,7 @@ parse(Tokens) ->
{error,{Reason,hd(Tokens)}};
{ModuleDefinition,Rest1} ->
{Types,Rest2} = parse_AssignmentList(Rest1),
+ clean_process_dictionary(),
case Rest2 of
[{'END',_}|_Rest3] ->
{ok,ModuleDefinition#module{typeorval = Types}};
@@ -48,6 +49,13 @@ parse(Tokens) ->
end
end.
+clean_process_dictionary() ->
+ Mod = erase(asn1_module),
+ _ = erase({Mod,imports}),
+ _ = erase(tagdefault),
+ _ = erase(extensiondefault),
+ ok.
+
parse_ModuleDefinition([{typereference,L1,ModuleIdentifier}|Rest0]) ->
put(asn1_module,ModuleIdentifier),
{_DefinitiveIdentifier,Rest02} =
diff --git a/lib/asn1/src/asn1ct_value.erl b/lib/asn1/src/asn1ct_value.erl
index 992210232f..862b3c4ea5 100644
--- a/lib/asn1/src/asn1ct_value.erl
+++ b/lib/asn1/src/asn1ct_value.erl
@@ -167,17 +167,16 @@ from_type_prim(M, D) ->
case D#type.def of
'INTEGER' ->
i_random(C);
- {'INTEGER',NamedNumberList} ->
- NN = [X||{X,_} <- NamedNumberList],
- case NN of
+ {'INTEGER',[_|_]=NNL} ->
+ case C of
[] ->
- i_random(C);
+ {N,_} = lists:nth(random(length(NNL)), NNL),
+ N;
_ ->
- case C of
- [] ->
- lists:nth(random(length(NN)),NN);
- _ ->
- lists:nth((fun(0)->1;(X)->X end(i_random(C))),NN)
+ V = i_random(C),
+ case lists:keyfind(V, 2, NNL) of
+ false -> V;
+ {N,V} -> N
end
end;
Enum when is_tuple(Enum),element(1,Enum)=='ENUMERATED' ->
diff --git a/lib/asn1/src/asn1rtt_check.erl b/lib/asn1/src/asn1rtt_check.erl
index e78b65a8fb..be4f9c8bff 100644
--- a/lib/asn1/src/asn1rtt_check.erl
+++ b/lib/asn1/src/asn1rtt_check.erl
@@ -20,7 +20,7 @@
-export([check_bool/2,
check_int/3,
- check_bitstring/3,
+ check_bitstring/2,check_named_bitstring/3,
check_octetstring/2,
check_null/2,
check_objectidentifier/2,
@@ -50,31 +50,54 @@ check_int(DefValue, Value, NNL) when is_atom(Value) ->
check_int(DefaultValue, _Value, _) ->
throw({error,DefaultValue}).
-%% Two equal lists or integers
-check_bitstring(_, asn1_DEFAULT, _) ->
+%% check_bitstring(Default, UserBitstring) -> true|false
+%% Default = bitstring()
+%% UserBitstring = integeger() | list(0|1) | {Unused,binary()} | bitstring()
+check_bitstring(_, asn1_DEFAULT) ->
true;
-check_bitstring(V, V, _) ->
- true;
-%% Default value as a list of 1 and 0 and user value as an integer
-check_bitstring(L=[H|T], Int, _) when is_integer(Int), is_integer(H) ->
- case bit_list_to_int(L, length(T)) of
- Int -> true;
- _ -> throw({error,L,Int})
+check_bitstring(DefVal, {Unused,Binary}) ->
+ %% User value in compact format.
+ Sz = bit_size(Binary) - Unused,
+ <<Val:Sz/bitstring,_:Unused>> = Binary,
+ check_bitstring(DefVal, Val);
+check_bitstring(DefVal, Val) when is_bitstring(Val) ->
+ case Val =:= DefVal of
+ false -> throw(error);
+ true -> true
end;
-%% Default value as an integer, val as list
-check_bitstring(Int, Val, NBL) when is_integer(Int), is_list(Val) ->
- BL = int_to_bit_list(Int, [], length(Val)),
- check_bitstring(BL, Val, NBL);
+check_bitstring(Def, Val) when is_list(Val) ->
+ check_bitstring_list(Def, Val);
+check_bitstring(Def, Val) when is_integer(Val) ->
+ check_bitstring_integer(Def, Val).
+
+check_bitstring_list(<<H:1,T1/bitstring>>, [H|T2]) ->
+ check_bitstring_list(T1, T2);
+check_bitstring_list(<<>>, []) ->
+ true;
+check_bitstring_list(_, _) ->
+ throw(error).
+
+check_bitstring_integer(<<H:1,T1/bitstring>>, Int) when H =:= Int band 1 ->
+ check_bitstring_integer(T1, Int bsr 1);
+check_bitstring_integer(<<>>, 0) ->
+ true;
+check_bitstring_integer(_, _) ->
+ throw(error).
+
+check_named_bitstring(_, asn1_DEFAULT, _) ->
+ true;
+check_named_bitstring(V, V, _) ->
+ true;
%% Default value and user value as lists of ones and zeros
-check_bitstring(L1=[H1|_T1], L2=[H2|_T2], NBL=[_H|_T]) when is_integer(H1), is_integer(H2) ->
+check_named_bitstring(L1=[H1|_T1], L2=[H2|_T2], NBL=[_H|_T]) when is_integer(H1), is_integer(H2) ->
L2new = remove_trailing_zeros(L2),
- check_bitstring(L1, L2new, NBL);
+ check_named_bitstring(L1, L2new, NBL);
%% Default value as a list of 1 and 0 and user value as a list of atoms
-check_bitstring(L1=[H1|_T1], L2=[H2|_T2], NBL) when is_integer(H1), is_atom(H2) ->
+check_named_bitstring(L1=[H1|_T1], L2=[H2|_T2], NBL) when is_integer(H1), is_atom(H2) ->
L3 = bit_list_to_nbl(L1, NBL, 0, []),
- check_bitstring(L3, L2, NBL);
+ check_named_bitstring(L3, L2, NBL);
%% Both default value and user value as a list of atoms
-check_bitstring(L1=[H1|T1], L2=[H2|_T2], _)
+check_named_bitstring(L1=[H1|T1], L2=[H2|_T2], _)
when is_atom(H1), is_atom(H2), length(L1) =:= length(L2) ->
case lists:member(H1, L2) of
true ->
@@ -82,27 +105,29 @@ check_bitstring(L1=[H1|T1], L2=[H2|_T2], _)
false -> throw({error,L2})
end;
%% Default value as a list of atoms and user value as a list of 1 and 0
-check_bitstring(L1=[H1|_T1], L2=[H2|_T2], NBL) when is_atom(H1), is_integer(H2) ->
+check_named_bitstring(L1=[H1|_T1], L2=[H2|_T2], NBL) when is_atom(H1), is_integer(H2) ->
L3 = bit_list_to_nbl(L2, NBL, 0, []),
- check_bitstring(L1, L3, NBL);
+ check_named_bitstring(L1, L3, NBL);
%% User value in compact format
-check_bitstring(DefVal,CBS={_,_}, NBL) ->
+check_named_bitstring(DefVal,CBS={_,_}, NBL) ->
NewVal = cbs_to_bit_list(CBS),
- check_bitstring(DefVal, NewVal, NBL);
-check_bitstring(DV, V, _) ->
+ check_named_bitstring(DefVal, NewVal, NBL);
+%% User value as a binary
+check_named_bitstring(DefVal, CBS, NBL) when is_binary(CBS) ->
+ NewVal = cbs_to_bit_list({0,CBS}),
+ check_named_bitstring(DefVal, NewVal, NBL);
+%% User value as a bitstring
+check_named_bitstring(DefVal, CBS, NBL) when is_bitstring(CBS) ->
+ BitSize = bit_size(CBS),
+ Unused = 8 - (BitSize band 7),
+ NewVal = cbs_to_bit_list({Unused,<<CBS:BitSize/bits,0:Unused>>}),
+ check_named_bitstring(DefVal, NewVal, NBL);
+check_named_bitstring(DV, V, _) ->
throw({error,DV,V}).
-
-bit_list_to_int([0|Bs], ShL)->
- bit_list_to_int(Bs, ShL-1) + 0;
-bit_list_to_int([1|Bs], ShL) ->
- bit_list_to_int(Bs, ShL-1) + (1 bsl ShL);
-bit_list_to_int([], _) ->
- 0.
-
int_to_bit_list(0, Acc, 0) ->
Acc;
-int_to_bit_list(Int, Acc, Len) ->
+int_to_bit_list(Int, Acc, Len) when Len > 0 ->
int_to_bit_list(Int bsr 1, [Int band 1|Acc], Len - 1).
bit_list_to_nbl([0|T], NBL, Pos, Acc) ->
diff --git a/lib/asn1/src/asn1rtt_per_common.erl b/lib/asn1/src/asn1rtt_per_common.erl
index 9e9fd87ec3..3309e6a4ca 100644
--- a/lib/asn1/src/asn1rtt_per_common.erl
+++ b/lib/asn1/src/asn1rtt_per_common.erl
@@ -37,6 +37,7 @@
bitstring_from_positions/1,bitstring_from_positions/2,
to_bitstring/1,to_bitstring/2,
to_named_bitstring/1,to_named_bitstring/2,
+ is_default_bitstring/5,
extension_bitmap/3]).
-define('16K',16384).
@@ -271,6 +272,36 @@ to_named_bitstring(Val, Lb) ->
%% for correctness, not speed.
adjust_trailing_zeroes(to_bitstring(Val), Lb).
+is_default_bitstring(asn1_DEFAULT, _, _, _, _) ->
+ true;
+is_default_bitstring({Unused,Bin}, V0, V1, V2, V3) when is_integer(Unused) ->
+ %% Convert compact bitstring to a bitstring.
+ Sz = bit_size(Bin) - Unused,
+ <<Bs:Sz/bitstring,_:Unused>> = Bin,
+ is_default_bitstring(Bs, V0, V1, V2, V3);
+is_default_bitstring(Named, Named, _, _, _) ->
+ true;
+is_default_bitstring(Bs, _, Bs, _, _) ->
+ true;
+is_default_bitstring(List, _, _, List, _) ->
+ true;
+is_default_bitstring(Int, _, _, _, Int) ->
+ true;
+is_default_bitstring(Val, _, Def, _, _) when is_bitstring(Val) ->
+ Sz = bit_size(Def),
+ case Val of
+ <<Def:Sz/bitstring,T/bitstring>> ->
+ NumZeroes = bit_size(T),
+ case T of
+ <<0:NumZeroes>> -> true;
+ _ -> false
+ end;
+ _ ->
+ false
+ end;
+is_default_bitstring(Val, _, _, List, _) when is_list(Val) ->
+ is_default_bitstring_list(List, Val);
+is_default_bitstring(_, _, _, _, _) -> false.
extension_bitmap(Val, Pos, Limit) ->
extension_bitmap(Val, Pos, Limit, 0).
@@ -447,6 +478,16 @@ ntz(Byte) ->
4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0},
element(Byte+1, T).
+is_default_bitstring_list([H|Def], [H|Val]) ->
+ is_default_bitstring_list(Def, Val);
+is_default_bitstring_list([], []) ->
+ true;
+is_default_bitstring_list([], [_|_]=Val) ->
+ lists:all(fun(0) -> true;
+ (_) -> false
+ end, Val);
+is_default_bitstring_list(_, _) -> false.
+
extension_bitmap(_Val, Pos, Limit, Acc) when Pos >= Limit ->
Acc;
extension_bitmap(Val, Pos, Limit, Acc) ->
diff --git a/lib/asn1/src/prepare_templates.erl b/lib/asn1/src/prepare_templates.erl
index 83155b2e52..ccd15548d8 100644
--- a/lib/asn1/src/prepare_templates.erl
+++ b/lib/asn1/src/prepare_templates.erl
@@ -21,69 +21,77 @@
-export([gen_asn1ct_rtt/1,gen_asn1ct_eval/1]).
gen_asn1ct_rtt(Ms) ->
- io:format("%% Generated by ~s. DO NOT EDIT THIS FILE.\n"
+ {ok,Fd} = file:open("asn1ct_rtt.erl", [write]),
+ io:format(Fd,
+ "%% Generated by ~s. DO NOT EDIT THIS FILE.\n"
"%%\n"
"%% Input files:\n", [?MODULE]),
- [io:put_chars(["%% ",M,$\n]) || M <- Ms],
- io:nl(),
- io:put_chars("-module(asn1ct_rtt).\n"
+ [io:put_chars(Fd, ["%% ",M,$\n]) || M <- Ms],
+ io:nl(Fd),
+ io:put_chars(Fd,
+ "-module(asn1ct_rtt).\n"
"-export([assert_defined/1,dependencies/1,code/0]).\n"
"\n"),
Forms = lists:sort(lists:append([abstract(M) || M <- Ms])),
Exp = lists:sort(exports(Forms)),
- defined(Exp),
- io:nl(),
+ defined(Fd, Exp),
+ io:nl(Fd),
Calls = calls(Forms),
R = sofs:relation(Calls),
Fam0 = sofs:relation_to_family(R),
Fam = sofs:to_external(Fam0),
- dependencies(Fam),
- io:nl(),
+ dependencies(Fd, Fam),
+ io:nl(Fd),
Funcs = [begin
Bin = list_to_binary([$\n|erl_pp:function(Func)]),
{{M,F,A},Bin}
end || {M,{function,_,F,A,_}=Func} <- Forms],
- io:format("code() ->\n~p.\n\n", [Funcs]),
+ io:format(Fd, "code() ->\n~p.\n\n", [Funcs]),
+ ok = file:close(Fd),
halt(0).
gen_asn1ct_eval([File]) ->
+ Output = filename:rootname(File, ".funcs") ++ ".erl",
+ {ok,Fd} = file:open(Output, [write]),
{ok,Funcs} = file:consult(File),
asn1ct_func:start_link(),
[asn1ct_func:need(MFA) || MFA <- Funcs],
- io:format("%% Generated by ~s. DO NOT EDIT THIS FILE.\n"
+ io:format(Fd,
+ "%% Generated by ~s. DO NOT EDIT THIS FILE.\n"
"%%\n"
"%% Input file: ~s\n\n", [?MODULE,File]),
- io:format("-module(~s).\n", [filename:rootname(File)]),
- gen_asn1ct_eval_exp(Funcs),
- asn1ct_func:generate(group_leader()),
+ io:format(Fd, "-module(~s).\n", [filename:rootname(File)]),
+ gen_asn1ct_eval_exp(Fd, Funcs),
+ asn1ct_func:generate(Fd),
+ ok = file:close(Fd),
halt(0).
-gen_asn1ct_eval_exp(Funcs) ->
- io:put_chars("-export(["),
- gen_asn1ct_eval_exp_1(Funcs, ""),
- io:put_chars("]).\n").
+gen_asn1ct_eval_exp(Fd, Funcs) ->
+ io:put_chars(Fd, "-export(["),
+ gen_asn1ct_eval_exp_1(Fd, Funcs, ""),
+ io:put_chars(Fd, "]).\n").
-gen_asn1ct_eval_exp_1([{_,F,A}|T], Sep) ->
- io:put_chars(Sep),
- io:format("~p/~p", [F,A]),
- gen_asn1ct_eval_exp_1(T, ",\n");
-gen_asn1ct_eval_exp_1([], _) -> ok.
+gen_asn1ct_eval_exp_1(Fd, [{_,F,A}|T], Sep) ->
+ io:put_chars(Fd, Sep),
+ io:format(Fd, "~p/~p", [F,A]),
+ gen_asn1ct_eval_exp_1(Fd, T, ",\n");
+gen_asn1ct_eval_exp_1(_, [], _) -> ok.
-defined([H|T]) ->
- io:format("assert_defined(~p) -> ok", [H]),
+defined(Fd, [H|T]) ->
+ io:format(Fd, "assert_defined(~p) -> ok", [H]),
case T of
[] ->
- io:put_chars(".\n");
+ io:put_chars(Fd, ".\n");
[_|_] ->
- io:put_chars(";\n"),
- defined(T)
+ io:put_chars(Fd, ";\n"),
+ defined(Fd, T)
end.
-dependencies([{K,V}|T]) ->
- io:format("dependencies(~p) ->\n~p;\n", [K,V]),
- dependencies(T);
-dependencies([]) ->
- io:put_chars("dependencies(_) -> [].\n").
+dependencies(Fd, [{K,V}|T]) ->
+ io:format(Fd, "dependencies(~p) ->\n~p;\n", [K,V]),
+ dependencies(Fd, T);
+dependencies(Fd, []) ->
+ io:put_chars(Fd, "dependencies(_) -> [].\n").
abstract(File) ->
{ok,{M0,[{abstract_code,Abstract}]}} =
diff --git a/lib/asn1/test/Makefile b/lib/asn1/test/Makefile
index a3fa4f2968..b1b08aa9f9 100644
--- a/lib/asn1/test/Makefile
+++ b/lib/asn1/test/Makefile
@@ -26,7 +26,6 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
MODULES= \
h323test \
- choice_extension \
ber_decode_error \
testPrim \
testPrimStrings \
@@ -36,7 +35,6 @@ MODULES= \
testChoExtension \
testChoExternal \
testChoOptional \
- testChoOptionalImplicitTag \
testChoRecursive \
testChoTypeRefCho \
testChoTypeRefPrim \
@@ -51,12 +49,12 @@ MODULES= \
testSeqOptional \
testSeq2738 \
testSeqPrim \
+ testSeqSetIndefinite \
testSeqTag \
testSeqTypeRefCho \
testSeqTypeRefPrim \
testSeqTypeRefSeq \
testSeqTypeRefSet \
- testSeqIndefinite \
testSeqOf \
testSeqOfIndefinite \
testSeqOfCho \
@@ -72,7 +70,6 @@ MODULES= \
testSetTypeRefPrim \
testSetTypeRefSeq \
testSetTypeRefSet \
- testSetIndefinite \
testChoiceIndefinite \
testSetOf \
testSetOfCho \
@@ -100,7 +97,6 @@ MODULES= \
test_special_decode_performance \
testTCAP \
testSSLspecs \
- test_driver_load \
testSelectionTypes \
test_undecoded_rest \
testTcapsystem \
@@ -114,12 +110,9 @@ MODULES= \
asn1_test_lib \
asn1_app_test \
asn1_appup_test \
- asn1_wrapper \
asn1_SUITE \
error_SUITE
-SUITE= asn1_SUITE.erl
-
ERL_FILES= $(MODULES:%=%.erl)
HRL_FILES= External.hrl
@@ -144,7 +137,7 @@ EBIN = .
$(EMAKEFILE): $(ERL_FILES) $(HRL_FILES)
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) $(ERL_FILES) >$(EMAKEFILE)
-tests debug opt: $(SUITE) $(SUITE_BIN) $(SUITE_BIN_V2) $(EMAKEFILE)
+tests debug opt: $(EMAKEFILE)
clean:
rm -f core
@@ -161,7 +154,7 @@ release_spec: opt
release_tests_spec: opt
$(INSTALL_DIR) "$(RELSYSDIR)"
$(INSTALL_DIR) "$(RELSYSDIR)/asn1_SUITE_data"
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)"
+ $(INSTALL_DATA) $(EMAKEFILE) $(ERL_FILES) $(HRL_FILES) "$(RELSYSDIR)"
$(INSTALL_DATA) asn1.spec asn1.cover $(INSTALL_PROGS) "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
cd asn1_SUITE_data; tar cfh "$(RELSYSDIR)/asn1_SUITE_data.tar" *
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index 9a149a495a..83bd66a631 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -67,10 +67,10 @@ groups() ->
{parallel, parallel([]),
[cover,
+ xref,
{group, ber},
% Uses 'P-Record', 'Constraints', 'MEDIA-GATEWAY-CONTROL'...
{group, [], [parse,
- test_driver_load,
test_undecoded_rest,
specialized_decodes,
special_decode_performance,
@@ -83,38 +83,24 @@ groups() ->
{group, [], [testPrim,
rtUI,
testPrimStrings,
- testInvokeMod,
per,
ber_other,
der,
- h323test,
- per_GeneralString]},
+ h323test]},
testChoPrim,
testChoExtension,
testChoOptional,
- testChoOptionalImplicitTag,
testChoRecursive,
testChoTypeRefCho,
testChoTypeRefPrim,
testChoTypeRefSeq,
testChoTypeRefSet,
testMultipleLevels,
- testDef,
testOpt,
testSeqDefault,
% Uses 'External'
- {group, [], [testChoExternal,
- testPrimExternal,
- testSeqExtension,
- testSeqExternal,
- testSeqOfExternal,
- testSeqOfTag,
- testSeqTag,
- testSetExtension,
- testSetExternal,
- testSetOfExternal,
- testSetOfTag,
- testSetTag]},
+ {group, [], [testExternal,
+ testSeqExtension]},
testSeqOptional,
testSeqPrim,
testSeqTypeRefCho,
@@ -143,9 +129,7 @@ groups() ->
% Uses 'Constructed'
{group, [], [constructed,
ber_decode_error]},
- % Uses 'SeqSetIndefinite'
- {group, [], [testSeqIndefinite,
- testSetIndefinite]},
+ testSeqSetIndefinite,
testChoiceIndefinite,
per_open_type,
testInfObjectClass,
@@ -156,9 +140,9 @@ groups() ->
testDeepTConstr,
testExport,
testImport,
- % Uses 'ParamBasic'
- {group, [], [testParamBasic,
- testDER]},
+ testParamBasic,
+ testDER,
+ testDEFAULT,
testMvrasn6,
testContextSwitchingTypes,
testOpenTypeImplicitTag,
@@ -284,13 +268,6 @@ replace_path(PathA, PathB) ->
join(Rule, Opts) ->
string:join([atom_to_list(Rule)|lists:map(fun atom_to_list/1, Opts)], "_").
-case_dir([], _Dir) ->
- exit(no_case_dir);
-case_dir([{case_dir, _}|Config], Dir) ->
- [{case_dir, Dir}|Config];
-case_dir([C|Config], Opt) ->
- [C|case_dir(Config, Opt)].
-
%%------------------------------------------------------------------------------
%% Test cases
%%------------------------------------------------------------------------------
@@ -319,7 +296,15 @@ cover(_) ->
testPrim(Config) -> test(Config, fun testPrim/3).
testPrim(Config, Rule, Opts) ->
- asn1_test_lib:compile_all(["Prim", "Real"], Config, [Rule|Opts]),
+ Files = ["Prim","Real"],
+ asn1_test_lib:compile_all(Files, Config, [Rule|Opts]),
+ do_test_prim(Rule, false),
+ asn1_test_lib:compile_all(Files, Config, [no_ok_wrapper,Rule|Opts]),
+ do_test_prim(Rule, true).
+
+do_test_prim(Rule, NoOkWrapper) ->
+ io:format("No ok wrapper: ~p\n", [NoOkWrapper]),
+ put(no_ok_wrapper, NoOkWrapper),
testPrim:bool(Rule),
testPrim:int(Rule),
testPrim:enum(Rule),
@@ -340,20 +325,21 @@ testCompactBitString(Config, Rule, Opts) ->
[Rule, compact_bit_string|Opts]),
testCompactBitString:otp_4869(Rule).
-testPrimStrings(Config) -> test(Config, fun testPrimStrings/3).
+testPrimStrings(Config) ->
+ test(Config, fun testPrimStrings/3, [ber,{ber,[der]},per,uper]).
testPrimStrings(Config, Rule, Opts) ->
asn1_test_lib:compile_all(["PrimStrings", "BitStr"], Config, [Rule|Opts]),
- testPrimStrings_cases(Rule),
+ testPrimStrings_cases(Rule, Opts),
asn1_test_lib:compile_all(["PrimStrings", "BitStr"], Config,
[legacy_bit_string,Rule|Opts]),
- testPrimStrings:bit_string(Rule),
+ testPrimStrings:bit_string(Rule, Opts),
asn1_test_lib:compile_all(["PrimStrings", "BitStr"], Config,
[compact_bit_string,Rule|Opts]),
- testPrimStrings:bit_string(Rule),
+ testPrimStrings:bit_string(Rule, Opts),
testPrimStrings:more_strings(Rule).
-testPrimStrings_cases(Rule) ->
- testPrimStrings:bit_string(Rule),
+testPrimStrings_cases(Rule, Opts) ->
+ testPrimStrings:bit_string(Rule, Opts),
testPrimStrings:octet_string(Rule),
testPrimStrings:numeric_string(Rule),
testPrimStrings:other_strings(Rule),
@@ -363,15 +349,33 @@ testPrimStrings_cases(Rule) ->
testPrimStrings:utf8_string(Rule),
testPrimStrings:fragmented(Rule).
-testPrimExternal(Config) -> test(Config, fun testPrimExternal/3).
-testPrimExternal(Config, Rule, Opts) ->
- asn1_test_lib:compile_all(["External", "PrimExternal"], Config,
- [Rule|Opts]),
+testExternal(Config) -> test(Config, fun testExternal/3).
+testExternal(Config, Rule, Opts) ->
+ asn1_test_lib:compile_all(["External",
+ "ChoExternal",
+ "PrimExternal",
+ "SeqExternal",
+ "SeqOfExternal",
+ "SeqOfTag",
+ "SeqTag",
+ "SetExtension",
+ "SetExternal",
+ "SetOfExternal",
+ "SetOfTag",
+ "SetTag"],
+ Config, [Rule|Opts]),
+ testChoExternal:external(Rule),
testPrimExternal:external(Rule),
- asn1_test_lib:compile_all(["PrimStrings", "BitStr"], Config,
- [Rule|Opts]),
- testPrimStrings_cases(Rule),
- testPrimStrings:more_strings(Rule).
+ testSeqExternal:main(Rule),
+ testSeqOfExternal:main(Rule),
+ testSeqOfTag:main(Rule),
+ testSeqTag:main(Rule),
+ testSetExtension:main(Rule),
+ testSetExternal:main(Rule),
+ testSetOfExternal:main(Rule),
+ testSetOfTag:main(Rule),
+ testSetTag:main(Rule).
+
testChoPrim(Config) -> test(Config, fun testChoPrim/3).
testChoPrim(Config, Rule, Opts) ->
@@ -384,23 +388,11 @@ testChoExtension(Config, Rule, Opts) ->
asn1_test_lib:compile("ChoExtension", Config, [Rule|Opts]),
testChoExtension:extension(Rule).
-testChoExternal(Config) -> test(Config, fun testChoExternal/3).
-testChoExternal(Config, Rule, Opts) ->
- asn1_test_lib:compile_all(["External", "ChoExternal"], Config, [Rule|Opts]),
- testChoExternal:external(Rule).
-
testChoOptional(Config) -> test(Config, fun testChoOptional/3).
testChoOptional(Config, Rule, Opts) ->
- asn1_test_lib:compile("ChoOptional", Config, [Rule|Opts]),
- testChoOptional:optional(Rule).
-
-testChoOptionalImplicitTag(Config) ->
- test(Config, fun testChoOptionalImplicitTag/3,
- [ber]).
-testChoOptionalImplicitTag(Config, Rule, Opts) ->
- %% Only meaningful for ber & co
- asn1_test_lib:compile("ChoOptionalImplicitTag", Config, [Rule|Opts]),
- testChoOptionalImplicitTag:optional(Rule).
+ asn1_test_lib:compile_all(["ChoOptional",
+ "ChoOptionalImplicitTag"], Config, [Rule|Opts]),
+ testChoOptional:run().
testChoRecursive(Config) -> test(Config, fun testChoRecursive/3).
testChoRecursive(Config, Rule, Opts) ->
@@ -437,6 +429,13 @@ testDef(Config, Rule, Opts) ->
asn1_test_lib:compile("Def", Config, [Rule|Opts]),
testDef:main(Rule).
+testDEFAULT(Config) ->
+ test(Config, fun testDEFAULT/3, [ber,{ber,[der]},per,uper]).
+testDEFAULT(Config, Rule, Opts) ->
+ asn1_test_lib:compile_all(["Def","Default"], Config, [Rule|Opts]),
+ testDef:main(Rule),
+ testSeqSetDefaultVal:main(Rule, Opts).
+
testOpt(Config) -> test(Config, fun testOpt/3).
testOpt(Config, Rule, Opts) ->
asn1_test_lib:compile("Opt", Config, [Rule|Opts]),
@@ -463,11 +462,6 @@ testSeqExtension(Config, Rule, Opts) ->
DataDir = ?config(data_dir, Config),
testSeqExtension:main(Rule, DataDir, [Rule|Opts]).
-testSeqExternal(Config) -> test(Config, fun testSeqExternal/3).
-testSeqExternal(Config, Rule, Opts) ->
- asn1_test_lib:compile_all(["External", "SeqExternal"], Config, [Rule|Opts]),
- testSeqExternal:main(Rule).
-
testSeqOptional(Config) -> test(Config, fun testSeqOptional/3).
testSeqOptional(Config, Rule, Opts) ->
asn1_test_lib:compile("SeqOptional", Config, [Rule|Opts]),
@@ -484,11 +478,6 @@ testSeq2738(Config, Rule, Opts) ->
asn1_test_lib:compile("Seq2738", Config, [Rule|Opts]),
testSeq2738:main(Rule).
-testSeqTag(Config) -> test(Config, fun testSeqTag/3).
-testSeqTag(Config, Rule, Opts) ->
- asn1_test_lib:compile_all(["External", "SeqTag"], Config, [Rule|Opts]),
- testSeqTag:main(Rule).
-
testSeqTypeRefCho(Config) -> test(Config, fun testSeqTypeRefCho/3).
testSeqTypeRefCho(Config, Rule, Opts) ->
asn1_test_lib:compile("SeqTypeRefCho", Config, [Rule|Opts]),
@@ -529,38 +518,17 @@ testSeqOfIndefinite(Config, Rule, Opts) ->
asn1_test_lib:compile_all(Files, Config, [Rule|Opts]),
testSeqOfIndefinite:main().
-testSeqOfExternal(Config) -> test(Config, fun testSeqOfExternal/3).
-testSeqOfExternal(Config, Rule, Opts) ->
- asn1_test_lib:compile_all(["External", "SeqOfExternal"], Config,
- [Rule|Opts]),
- testSeqOfExternal:main(Rule).
-
-testSeqOfTag(Config) -> test(Config, fun testSeqOfTag/3).
-testSeqOfTag(Config, Rule, Opts) ->
- asn1_test_lib:compile_all(["External", "SeqOfTag"], Config, [Rule|Opts]),
- testSeqOfTag:main(Rule).
-
testSetDefault(Config) -> test(Config, fun testSetDefault/3).
testSetDefault(Config, Rule, Opts) ->
asn1_test_lib:compile("SetDefault", Config, [Rule|Opts]),
testSetDefault:main(Rule).
-testParamBasic(Config) -> test(Config, fun testParamBasic/3).
+testParamBasic(Config) ->
+ test(Config, fun testParamBasic/3, [ber,{ber,[der]},per,uper]).
testParamBasic(Config, Rule, Opts) ->
asn1_test_lib:compile("ParamBasic", Config, [Rule|Opts]),
testParamBasic:main(Rule).
-testSetExtension(Config) -> test(Config, fun testSetExtension/3).
-testSetExtension(Config, Rule, Opts) ->
- asn1_test_lib:compile_all(["External", "SetExtension"], Config,
- [Rule|Opts]),
- testSetExtension:main(Rule).
-
-testSetExternal(Config) -> test(Config, fun testSetExternal/3).
-testSetExternal(Config, Rule, Opts) ->
- asn1_test_lib:compile_all(["External", "SetExternal"], Config, [Rule|Opts]),
- testSetExternal:main(Rule).
-
testSetOptional(Config) -> test(Config, fun testSetOptional/3).
testSetOptional(Config, Rule, Opts) ->
asn1_test_lib:compile("SetOptional", Config, [Rule|Opts]),
@@ -572,11 +540,6 @@ testSetPrim(Config, Rule, Opts) ->
asn1_test_lib:compile("SetPrim", Config, [Rule|Opts]),
testSetPrim:main(Rule).
-testSetTag(Config) -> test(Config, fun testSetTag/3).
-testSetTag(Config, Rule, Opts) ->
- asn1_test_lib:compile_all(["External", "SetTag"], Config, [Rule|Opts]),
- testSetTag:main(Rule).
-
testSetTypeRefCho(Config) -> test(Config, fun testSetTypeRefCho/3).
testSetTypeRefCho(Config, Rule, Opts) ->
asn1_test_lib:compile("SetTypeRefCho", Config, [Rule|Opts]),
@@ -607,17 +570,6 @@ testSetOfCho(Config, Rule, Opts) ->
asn1_test_lib:compile("SetOfCho", Config, [Rule|Opts]),
testSetOfCho:main(Rule).
-testSetOfExternal(Config) -> test(Config, fun testSetOfExternal/3).
-testSetOfExternal(Config, Rule, Opts) ->
- asn1_test_lib:compile_all(["External", "SetOfExternal"], Config,
- [Rule|Opts]),
- testSetOfExternal:main(Rule).
-
-testSetOfTag(Config) -> test(Config, fun testSetOfTag/3).
-testSetOfTag(Config, Rule, Opts) ->
- asn1_test_lib:compile_all(["External", "SetOfTag"], Config, [Rule|Opts]),
- testSetOfTag:main(Rule).
-
c_syntax(Config) ->
DataDir = ?config(data_dir, Config),
[{error, _} = asn1ct:compile(filename:join(DataDir, F))
@@ -715,10 +667,7 @@ ber_optional(Config, Rule, Opts) ->
V = {'S', {'A', 10, asn1_NOVALUE, asn1_NOVALUE},
{'B', asn1_NOVALUE, asn1_NOVALUE, asn1_NOVALUE},
{'C', asn1_NOVALUE, 111, asn1_NOVALUE}},
- {ok, B} = asn1_wrapper:encode('SOpttest', 'S', V),
- Bytes = lists:flatten(B),
- V2 = asn1_wrapper:decode('SOpttest', 'S', Bytes),
- V = element(2, V2).
+ asn1_test_lib:roundtrip('SOpttest', 'S', V).
%% records used by test-case default
-record('Def1', {bool0,
@@ -729,14 +678,16 @@ ber_optional(Config, Rule, Opts) ->
default(Config) -> test(Config, fun default/3).
default(Config, Rule, Opts) ->
asn1_test_lib:compile("Def", Config, [Rule|Opts]),
- {ok, Bytes1} = asn1_wrapper:encode('Def', 'Def1', #'Def1'{bool0 = true}),
- {ok, {'Def1', true, false, false, false}} =
- asn1_wrapper:decode('Def', 'Def1', lists:flatten(Bytes1)),
-
- {ok, Bytes2} = asn1_wrapper:encode('Def', 'Def1', #'Def1'{bool0 = true,
- bool2 = false}),
- {ok, {'Def1', true, false, false, false}} =
- asn1_wrapper:decode('Def', 'Def1', lists:flatten(Bytes2)).
+ asn1_test_lib:roundtrip('Def',
+ 'Def1',
+ #'Def1'{bool0=true},
+ #'Def1'{bool0=true,bool1=false,
+ bool2=false,bool3=false}),
+ asn1_test_lib:roundtrip('Def',
+ 'Def1',
+ #'Def1'{bool0=true,bool2=false},
+ #'Def1'{bool0=true,bool1=false,
+ bool2=false,bool3=false}).
value_test(Config) -> test(Config, fun value_test/3).
value_test(Config, Rule, Opts) ->
@@ -748,12 +699,13 @@ constructed(Config) ->
test(Config, fun constructed/3, [ber]).
constructed(Config, Rule, Opts) ->
asn1_test_lib:compile("Constructed", Config, [Rule|Opts]),
- {ok, B} = asn1_wrapper:encode('Constructed', 'S', {'S', false}),
- [40, 3, 1, 1, 0] = lists:flatten(B),
- {ok, B1} = asn1_wrapper:encode('Constructed', 'S2', {'S2', false}),
- [40, 5, 48, 3, 1, 1, 0] = lists:flatten(B1),
- {ok, B2} = asn1_wrapper:encode('Constructed', 'I', 10),
- [136, 1, 10] = lists:flatten(B2).
+ <<40,3,1,1,0>> =
+ asn1_test_lib:roundtrip_enc('Constructed', 'S', {'S',false}),
+ <<40,5,48,3,1,1,0>> =
+ asn1_test_lib:roundtrip_enc('Constructed', 'S2', {'S2',false}),
+ <<136,1,10>> =
+ asn1_test_lib:roundtrip_enc('Constructed', 'I', 10),
+ ok.
ber_decode_error(Config) ->
test(Config, fun ber_decode_error/3, [ber]).
@@ -768,14 +720,6 @@ h323test(Config, Rule, Opts) ->
asn1_test_lib:compile_all(Files, Config, [Rule|Opts]),
h323test:run(Rule).
-per_GeneralString(Config) ->
- test(Config, fun per_GeneralString/3, [per]).
-per_GeneralString(Config, Rule, Opts) ->
- asn1_test_lib:compile("MULTIMEDIA-SYSTEM-CONTROL", Config, [Rule|Opts]),
- UI = [109, 64, 1, 57],
- {ok, _V} = asn1_wrapper:decode('MULTIMEDIA-SYSTEM-CONTROL',
- 'MultimediaSystemControlMessage', UI).
-
per_open_type(Config) -> test(Config, fun per_open_type/3, [per]).
per_open_type(Config, Rule, Opts) ->
asn1_test_lib:compile("OpenType", Config, [Rule|Opts]),
@@ -785,24 +729,17 @@ testConstraints(Config) -> test(Config, fun testConstraints/3).
testConstraints(Config, Rule, Opts) ->
asn1_test_lib:compile("Constraints", Config, [Rule|Opts]),
asn1_test_lib:compile("LargeConstraints", Config, [Rule|Opts]),
- testConstraints:int_constraints(Rule).
-
-
-testSeqIndefinite(Config) ->
- test(Config, fun testSeqIndefinite/3, [ber]).
-
-testSeqIndefinite(Config, Rule, Opts) ->
- asn1_test_lib:compile("SeqSetIndefinite", Config, [Rule|Opts]),
- testSeqIndefinite:main(Rule).
-
-
-testSetIndefinite(Config) ->
- test(Config, fun testSetIndefinite/3, [ber]).
+ testConstraints:int_constraints(Rule),
+ case Rule of
+ ber -> ok;
+ _ -> testConstraints:refed_NNL_name(Rule)
+ end.
-testSetIndefinite(Config, Rule, Opts) ->
+testSeqSetIndefinite(Config) ->
+ test(Config, fun testSeqSetIndefinite/3, [ber]).
+testSeqSetIndefinite(Config, Rule, Opts) ->
asn1_test_lib:compile("SeqSetIndefinite", Config, [Rule|Opts]),
- testSetIndefinite:main(Rule).
-
+ testSeqSetIndefinite:main().
testChoiceIndefinite(Config) ->
test(Config, fun testChoiceIndefinite/3, [ber]).
@@ -858,11 +795,6 @@ testDeepTConstr(Config, Rule, Opts) ->
[Rule|Opts]),
testDeepTConstr:main(Rule).
-testInvokeMod(Config) -> test(Config, fun testInvokeMod/3).
-testInvokeMod(Config, Rule, Opts) ->
- asn1_test_lib:compile("PrimStrings", Config, [Rule|Opts]),
- {ok, _Result2} = 'PrimStrings':encode('Bs1', [1, 0, 1, 0]).
-
testExport(Config) ->
{error, _} =
asn1ct:compile(filename:join(?config(data_dir, Config),
@@ -918,7 +850,10 @@ duplicate_tags(Config) ->
rtUI(Config) -> test(Config, fun rtUI/3).
rtUI(Config, Rule, Opts) ->
asn1_test_lib:compile("Prim", Config, [Rule|Opts]),
- {ok, _} = asn1rt:info('Prim').
+ {ok, _} = asn1rt:info('Prim'),
+ Rule = 'Prim':encoding_rule(),
+ io:format("Default BIT STRING format: ~p\n",
+ ['Prim':bit_string_format()]).
testROSE(Config) -> test(Config, fun testROSE/3).
testROSE(Config, Rule, Opts) ->
@@ -946,11 +881,7 @@ testDER(Config) ->
test(Config, fun testDER/3, [ber]).
testDER(Config, Rule, Opts) ->
asn1_test_lib:compile("DERSpec", Config, [Rule, der|Opts]),
- testDER:test(),
- asn1_test_lib:compile("ParamBasic", Config, [Rule, der|Opts]),
- testParamBasic:main(der),
- asn1_test_lib:compile("Default", Config, [Rule, der|Opts]),
- testSeqSetDefaultVal:main(Rule).
+ testDER:test().
specialized_decodes(Config) ->
test(Config, fun specialized_decodes/3, [ber]).
@@ -972,13 +903,6 @@ special_decode_performance(Config, Rule, Opts) ->
asn1_test_lib:compile_all(Files, Config, [Rule, asn1config|Opts]),
test_special_decode_performance:go(all).
-
-test_driver_load(Config) ->
- test(Config, fun test_driver_load/3, [per]).
-test_driver_load(Config, Rule, Opts) ->
- asn1_test_lib:compile("P-Record", Config, [Rule|Opts]),
- test_driver_load:test(5).
-
test_ParamTypeInfObj(Config) ->
asn1_test_lib:compile("IN-CS-1-Datatypes", Config, [ber]).
@@ -996,7 +920,7 @@ test_Defed_ObjectIdentifier(Config, Rule, Opts) ->
testSelectionType(Config) -> test(Config, fun testSelectionType/3).
testSelectionType(Config, Rule, Opts) ->
asn1_test_lib:compile("SelectionType", Config, [Rule|Opts]),
- {ok, _} = testSelectionTypes:test().
+ testSelectionTypes:test().
testSSLspecs(Config) ->
test(Config, fun testSSLspecs/3, [ber]).
@@ -1013,10 +937,14 @@ testNortel(Config, Rule, Opts) ->
test_undecoded_rest(Config) -> test(Config, fun test_undecoded_rest/3).
test_undecoded_rest(Config, Rule, Opts) ->
+ do_test_undecoded_rest(Config, Rule, Opts),
+ do_test_undecoded_rest(Config, Rule, [no_ok_wrapper|Opts]),
+ do_test_undecoded_rest(Config, Rule, [undec_rest|Opts]),
+ do_test_undecoded_rest(Config, Rule, [no_ok_wrapper,undec_rest|Opts]).
+
+do_test_undecoded_rest(Config, Rule, Opts) ->
asn1_test_lib:compile("P-Record", Config, [Rule|Opts]),
- ok = test_undecoded_rest:test([], Config),
- asn1_test_lib:compile("P-Record", Config, [Rule,undec_rest|Opts]),
- test_undecoded_rest:test(undec_rest, Config).
+ test_undecoded_rest:test(Opts, Config).
testTcapsystem(Config) ->
test(Config, fun testTcapsystem/3).
@@ -1036,7 +964,20 @@ testS1AP(Config, Rule, Opts) ->
"S1AP-IEs",
"S1AP-PDU-Contents",
"S1AP-PDU-Descriptions"],
- asn1_test_lib:compile_all(S1AP, Config, [Rule|Opts]).
+ asn1_test_lib:compile_all(S1AP, Config, [Rule|Opts]),
+
+ %% OTP-7876.
+ case Rule of
+ per ->
+ Enc = <<0,2,64,49,0,0,5,0,0,0,4,128,106,56,197,0,8,0,3,64,2,134,0,
+ 100,64,8,0,66,240,153,0,7,192,16,0,67,64,6,0,66,240,153,70,
+ 1,0,107,64,5,0,0,0,0,0>>,
+ {ok,{initiatingMessage,_}} = 'S1AP-PDU-Descriptions':decode('S1AP-PDU', Enc);
+ uper ->
+ ok;
+ ber ->
+ ok
+ end.
test_compile_options(Config) ->
ok = test_compile_options:wrong_path(Config),
@@ -1068,24 +1009,38 @@ testX420(Config) ->
"sparc-sun-solaris2.10" ->
{skip,"Too slow for an old Sparc"};
_ ->
- test(Config, fun testX420/3, [ber])
+ Rule = ber,
+ testX420:compile(Rule, [der], Config),
+ ok = testX420:ticket7759(Rule, Config)
end.
-testX420(Config, Rule, Opts) ->
- testX420:compile(Rule, [der|Opts], Config),
- ok = testX420:ticket7759(Rule, Config),
- testX420:compile(Rule, Opts, Config).
test_x691(Config) ->
test(Config, fun test_x691/3, [per, uper]).
test_x691(Config, Rule, Opts) ->
Files = ["P-RecordA1", "P-RecordA2", "P-RecordA3"],
asn1_test_lib:compile_all(Files, Config, [Rule|Opts]),
- test_x691:cases(Rule, case Rule of
- uper -> unaligned;
- _ -> aligned
- end),
- asn1_test_lib:ticket_7708(Config, []),
- asn1_test_lib:ticket_7763(Config).
+ test_x691:cases(Rule),
+
+ %% OTP-7708.
+ asn1_test_lib:compile("EUTRA-extract-55", Config, [Rule|Opts]),
+
+ %% OTP-7763.
+ Val = {'Seq',15,lists:duplicate(8, 0),[0],lists:duplicate(28, 0),15,true},
+ CompactVal = {'Seq',15,{0,<<0>>},{7,<<0>>},{4,<<0,0,0,0>>},15,true},
+ {ok,Bin} = 'EUTRA-extract-55':encode('Seq', Val),
+ {ok,Bin} = 'EUTRA-extract-55':encode('Seq', CompactVal),
+
+ %% OTP-7678.
+ asn1_test_lib:compile("UPERDefault", Config, [Rule|Opts]),
+ DefVal = 'UPERDefault':seq(),
+ {ok,DefBin} = 'UPERDefault':encode('Seq', DefVal),
+ {ok,DefVal} = 'UPERDefault':decode('Seq', DefBin),
+ case Rule of
+ uper -> <<0,6,0>> = DefBin;
+ _ -> ok
+ end,
+
+ ok.
ticket_6143(Config) ->
ok = test_compile_options:ticket_6143(Config).
@@ -1193,9 +1148,7 @@ testTimer_uper(Config) ->
testComment(suite) -> [];
testComment(Config) ->
asn1_test_lib:compile("Comment", Config, []),
- {ok,Enc} = asn1_wrapper:encode('Comment','Seq',{'Seq',12,true}),
- {ok,{'Seq',12,true}} = asn1_wrapper:decode('Comment','Seq',Enc),
- ok.
+ asn1_test_lib:roundtrip('Comment', 'Seq', {'Seq',12,true}).
testName2Number(suite) -> [];
testName2Number(Config) ->
@@ -1231,11 +1184,66 @@ testName2Number(Config) ->
ticket_7407(Config) ->
asn1_test_lib:compile("EUTRA-extract-7407", Config, [uper]),
- asn1_test_lib:ticket_7407_code(true),
+ ticket_7407_code(true),
+ asn1_test_lib:compile("EUTRA-extract-7407", Config, [uper,no_final_padding]),
+ ticket_7407_code(false).
+
+ticket_7407_code(FinalPadding) ->
+ Msg1 = {Type1,_} = eutra1(msg),
+ {ok,B1} = 'EUTRA-extract-7407':encode(Type1, Msg1),
+ B1 = eutra1(result, FinalPadding),
+
+ Msg2 = {Type2,_} = eutra2(msg),
+ {ok,B2} = 'EUTRA-extract-7407':encode(Type2, Msg2),
+ B2 = eutra2(result, FinalPadding),
+ ok.
- asn1_test_lib:compile("EUTRA-extract-7407", Config,
- [uper, no_final_padding]),
- asn1_test_lib:ticket_7407_code(false).
+eutra1(msg) ->
+ {'BCCH-BCH-Message',
+ {'MasterInformationBlock',[0,1,0,1],[1,0,1,0],
+ {'PHICH-Configuration',short,ffs},[1,0,1,0,0,0,0,0]}}.
+
+eutra1(result, true) ->
+ <<90,80,0>>;
+eutra1(result, false) ->
+ <<90,80,0:1>>.
+
+eutra2(msg) ->
+ {'BCCH-DL-SCH-Message',
+ {c1,
+ {systemInformation1,
+ {'SystemInformationBlockType1',
+ {'SystemInformationBlockType1_cellAccessRelatedInformation',
+ [{'SystemInformationBlockType1_cellAccessRelatedInformation_plmn-IdentityList_SEQOF',
+ {'PLMN-Identity'},true},
+ {'SystemInformationBlockType1_cellAccessRelatedInformation_plmn-IdentityList_SEQOF',
+ {'PLMN-Identity'},false},
+ {'SystemInformationBlockType1_cellAccessRelatedInformation_plmn-IdentityList_SEQOF',
+ {'PLMN-Identity'},true}],
+ {'TrackingAreaCode'},
+ {'CellIdentity'},
+ false,
+ true,
+ true,
+ true
+ },
+ {'SystemInformationBlockType1_cellSelectionInfo',-50},
+ 24,
+ [{'SystemInformationBlockType1_schedulinInformation_SEQOF',
+ {'SystemInformationBlockType1_schedulinInformation_SEQOF_si-MessageType'},
+ ms320,
+ {'SystemInformationBlockType1_schedulinInformation_SEQOF_sib-MappingInfo'}}],
+ 0
+ }
+ }
+ }
+ }.
+
+eutra2(result, true) ->
+%% 55 5C A5 E0
+ <<85,92,165,224>>;
+eutra2(result, false) ->
+ <<85,92,165,14:4>>.
-record('InitiatingMessage',{procedureCode,criticality,value}).
-record('Iu-ReleaseCommand',{first,second}).
@@ -1251,3 +1259,17 @@ ticket7904(Config) ->
{ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1),
{ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1).
+
+xref(_Config) ->
+ xref:start(s),
+ xref:set_default(s, [{verbose,false},{warnings,false},{builtins,true}]),
+ Test = filename:dirname(code:which(?MODULE)),
+ {ok,_PMs} = xref:add_directory(s, Test),
+ UnusedExports = "X - XU - asn1_appup_test - asn1_app_test - \".*_SUITE\" : Mod",
+ case xref:q(s, UnusedExports) of
+ {ok,[]} ->
+ ok;
+ {ok,[_|_]=Res} ->
+ io:format("Exported, but unused: ~p\n", [Res]),
+ ?t:fail()
+ end.
diff --git a/lib/asn1/test/asn1_SUITE_data/Constraints.py b/lib/asn1/test/asn1_SUITE_data/Constraints.py
index e4bc987e4c..581ec2f467 100644
--- a/lib/asn1/test/asn1_SUITE_data/Constraints.py
+++ b/lib/asn1/test/asn1_SUITE_data/Constraints.py
@@ -17,6 +17,11 @@ NegSemiConstrained ::= INTEGER (-128..MAX)
SemiConstrainedExt ::= INTEGER (42..MAX, ...)
NegSemiConstrainedExt ::= INTEGER (-128..MAX, ...)
+-- Union of single values
+Sv1 ::= INTEGER (2|3|17)
+Sv2 ::= INTEGER (2|3|17, ...)
+Sv3 ::= INTEGER {a(2),b(3),z(17)} (2|3|17, ...)
+
-- Other constraints
FixedSize ::= OCTET STRING (SIZE(10))
FixedSize2 ::= OCTET STRING (SIZE(10|20))
diff --git a/lib/asn1/test/asn1_SUITE_data/Default.asn b/lib/asn1/test/asn1_SUITE_data/Default.asn
index 6604953c1f..168ce50bb2 100644
--- a/lib/asn1/test/asn1_SUITE_data/Default.asn
+++ b/lib/asn1/test/asn1_SUITE_data/Default.asn
@@ -21,7 +21,8 @@ SeqBS ::= SEQUENCE {
a BIT STRING DEFAULT '1010110'B,
b BIT STRING DEFAULT 'A8A'H,
c BIT STRING {first(0),second(1),third(2)} DEFAULT {second},
- d BIT STRING DEFAULT onelist
+ d BIT STRING DEFAULT onelist,
+ e BIT STRING DEFAULT '01011010'B
}
SetBS ::= SET {
diff --git a/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1 b/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1
index 08e7f94ab6..a5b4c8a53d 100644
--- a/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/PrimStrings.asn1
@@ -46,7 +46,13 @@ BS256 ::= BIT STRING (SIZE (256))
BS1024 ::= BIT STRING (SIZE (1024))
-
+ BsDef1 ::= SEQUENCE {
+ s BIT STRING DEFAULT '101111'B
+ }
+
+ BsDef2 ::= SEQUENCE {
+ s BIT STRING DEFAULT 'DEADBEEF'H
+ }
Os ::= OCTET STRING
OsCon ::= [60] OCTET STRING
diff --git a/lib/asn1/test/asn1_SUITE_data/UPERDefault.asn b/lib/asn1/test/asn1_SUITE_data/UPERDefault.asn
new file mode 100644
index 0000000000..7b81a0e09f
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/UPERDefault.asn
@@ -0,0 +1,18 @@
+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_test_lib.erl b/lib/asn1/test/asn1_test_lib.erl
index 60b2b2b42e..417380159e 100644
--- a/lib/asn1/test/asn1_test_lib.erl
+++ b/lib/asn1/test/asn1_test_lib.erl
@@ -19,13 +19,9 @@
%%
-module(asn1_test_lib).
--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]).
+-export([compile/3,compile_all/3,compile_erlang/3,
+ hex_to_bin/1,
+ roundtrip/3,roundtrip/4,roundtrip_enc/3,roundtrip_enc/4]).
-include_lib("test_server/include/test_server.hrl").
@@ -40,15 +36,7 @@ compile_all(Files, Config, Options) ->
compile_file(File, Options) ->
try
- ok = asn1ct:compile(File, [warnings_as_errors|Options]),
- case should_load(File, Options) of
- false ->
- ok;
- {module, Module} ->
- code:purge(Module),
- {module, Module} = code:load_file(Module),
- code:purge(Module)
- end
+ ok = asn1ct:compile(File, [warnings_as_errors|Options])
catch
Class:Reason ->
ct:print("Failed to compile ~s\n", [File]),
@@ -65,153 +53,26 @@ compile_erlang(Mod, Config, Options) ->
hex_to_bin(S) ->
<< <<(hex2num(C)):4>> || C <- S, C =/= $\s >>.
-%%%
-%%% Internal functions.
-%%%
+roundtrip(Mod, Type, Value) ->
+ roundtrip(Mod, Type, Value, Value).
-should_load(File, Options) ->
- case lists:member(abs, Options) of
- true ->
- false;
- false ->
- {module,list_to_atom(strip_extension(filename:basename(File)))}
- end.
+roundtrip(Mod, Type, Value, ExpectedValue) ->
+ {ok,Encoded} = Mod:encode(Type, Value),
+ {ok,ExpectedValue} = Mod:decode(Type, Encoded),
+ ok.
-strip_extension(File) ->
- strip_extension(File, filename:extension(File)).
+roundtrip_enc(Mod, Type, Value) ->
+ roundtrip_enc(Mod, Type, Value, Value).
-strip_extension(File, "") ->
- File;
-strip_extension(File, Ext) when Ext == ".asn"; Ext == ".set"; Ext == ".asn1"->
- strip_extension(filename:rootname(File));
-strip_extension(File, _Ext) ->
- File.
+roundtrip_enc(Mod, Type, Value, ExpectedValue) ->
+ {ok,Encoded} = Mod:encode(Type, Value),
+ {ok,ExpectedValue} = Mod:decode(Type, Encoded),
+ Encoded.
+
+%%%
+%%% Internal functions.
+%%%
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),
- ?line OutDir = ?config(priv_dir,Config),
-
- ?line ok = asn1ct:compile(DataDir ++ "EUTRA-extract-7407",
- [uper, {outdir,OutDir}]++Option).
-
-ticket_7708(Config,Option) ->
- ?line DataDir = ?config(data_dir,Config),
- ?line OutDir = ?config(priv_dir,Config),
-
- ?line ok = asn1ct:compile(DataDir ++ "EUTRA-extract-55",
- [uper, {outdir,OutDir}]++Option).
-
-
-ticket_7407_code(FinalPadding) ->
- Msg1 = {Type1,_} = eutra1(msg),
- ?line {ok,B1} = 'EUTRA-extract-7407':encode(Type1,Msg1),
- ?line B1 = eutra1(result,FinalPadding),
-
- Msg2 = {Type2,_} = eutra2(msg),
- ?line {ok,B2} = 'EUTRA-extract-7407':encode(Type2,Msg2),
- ?line B2 = eutra2(result,FinalPadding),
- ok.
-
-eutra1(msg) ->
- {'BCCH-BCH-Message',{'MasterInformationBlock',[0,1,0,1],[1,0,1,0],{'PHICH-Configuration',short,ffs},[1,0,1,0,0,0,0,0]}}.
-eutra1(result,true) ->
- <<90,80,0>>;
-eutra1(result,false) ->
- <<90,80,0:1>>.
-
-eutra2(msg) ->
- {'BCCH-DL-SCH-Message',
- {c1,
- {systemInformation1,
- {'SystemInformationBlockType1',
- {'SystemInformationBlockType1_cellAccessRelatedInformation',
- [{'SystemInformationBlockType1_cellAccessRelatedInformation_plmn-IdentityList_SEQOF',{'PLMN-Identity'},true},
- {'SystemInformationBlockType1_cellAccessRelatedInformation_plmn-IdentityList_SEQOF',{'PLMN-Identity'},false},
- {'SystemInformationBlockType1_cellAccessRelatedInformation_plmn-IdentityList_SEQOF',{'PLMN-Identity'},true}],
- {'TrackingAreaCode'},
- {'CellIdentity'},
- false,
- true,
- true,
- true
- },
- {'SystemInformationBlockType1_cellSelectionInfo',-50},
- 24,
- [{'SystemInformationBlockType1_schedulinInformation_SEQOF',
- {'SystemInformationBlockType1_schedulinInformation_SEQOF_si-MessageType'},
- ms320,
- {'SystemInformationBlockType1_schedulinInformation_SEQOF_sib-MappingInfo'}}],
- 0
- }
- }
- }
- }.
-eutra2(result,true) ->
-%% 55 5C A5 E0
- <<85,92,165,224>>;
-eutra2(result,false) ->
- <<85,92,165,14:4>>.
-
-
-
-ticket_7678(Config, Option) ->
- ?line DataDir = ?config(data_dir,Config),
- ?line OutDir = ?config(priv_dir,Config),
-
- ?line ok = asn1ct:compile(DataDir ++ "UPERDefault",
- [uper, {outdir,OutDir}]++Option),
-
- ?line Val = 'UPERDefault':seq(),
- ?line {ok,<<0,6,0>>} = 'UPERDefault':encode('Seq',Val),
- ?line {ok,Val} = 'UPERDefault':decode('Seq',<<0,6,0>>),
- ok.
-
-
-ticket_7763(Config) ->
- ?line DataDir = ?config(data_dir,Config),
- ?line OutDir = ?config(priv_dir,Config),
-
- ?line ok = asn1ct:compile(DataDir ++ "EUTRA-extract-55",
- [uper, {outdir,OutDir}]),
- Val = {'Seq',15,lists:duplicate(8,0),[0],lists:duplicate(28,0),15,true},
- ?line {ok,Bin} = 'EUTRA-extract-55':encode('Seq',Val),
-
- ?line ok = asn1ct:compile(DataDir ++ "EUTRA-extract-55",
- [uper,compact_bit_string,{outdir,OutDir}]),
- CompactVal = {'Seq',15,{0,<<0>>},{7,<<0>>},{4,<<0,0,0,0>>},15,true},
- {ok,CompactBin} = 'EUTRA-extract-55':encode('Seq',CompactVal),
-
- ?line Bin = CompactBin,
-
- io:format("CompactBin:~n~p~nBin:~n~p~nCompactBin == Bin is ~p~n",[CompactBin,Bin,CompactBin == Bin]).
-
-
-ticket_7876(Config,Erule,Options) ->
- ?line DataDir = ?config(data_dir,Config),
- ?line OutDir = ?config(priv_dir,Config),
-
- ?line ok = asn1ct:compile(DataDir ++ "S1AP-CommonDataTypes",
- [Erule,{outdir,OutDir}|Options]),
- ?line ok = asn1ct:compile(DataDir ++ "S1AP-Constants",
- [Erule,{outdir,OutDir}|Options]),
-?line ok = asn1ct:compile(DataDir ++ "S1AP-Containers",
- [Erule,{outdir,OutDir}|Options]),
-?line ok = asn1ct:compile(DataDir ++ "S1AP-IEs",
- [Erule,{outdir,OutDir}|Options]),
-?line ok = asn1ct:compile(DataDir ++ "S1AP-PDU-Contents",
- [Erule,{outdir,OutDir}|Options]),
-?line ok = asn1ct:compile(DataDir ++ "S1AP-PDU-Descriptions",
- [Erule,{outdir,OutDir}|Options]),
-
- ticket_7876_encdec(Erule),
- ok.
-
-ticket_7876_encdec(per) ->
- ?line {ok,{initiatingMessage,_}} = 'S1AP-PDU-Descriptions':decode('S1AP-PDU', [0,2,64,49,0,0,5,0,0,0,4,128,106,56,197,0,8,0,3,64,2,134,0,100,64,8,0,66,240,153,0,7,192,16,0,67,64,6,0,66,240,153,70,1,0,107,64,5,0,0,0,0,0]);
-ticket_7876_encdec(_) ->
- ?line {ok,{initiatingMessage,_}} = 'S1AP-PDU-Descriptions':decode('S1AP-PDU', <<0,2,64,49,0,0,5,0,0,0,4,128,106,56,197,0,8,0,3,64,2,134,0,100,64,8,0,66,240,153,0,7,192,16,0,67,64,6,0,66,240,153,70,1,0,107,64,5,0,0,0,0,0>>).
diff --git a/lib/asn1/test/asn1_wrapper.erl b/lib/asn1/test/asn1_wrapper.erl
deleted file mode 100644
index ac194fe38b..0000000000
--- a/lib/asn1/test/asn1_wrapper.erl
+++ /dev/null
@@ -1,49 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2001-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(asn1_wrapper).
--author('kenneth@bilbo').
-
--compile(export_all).
-%%-export([Function/Arity, ...]).
-
-
-encode(Module,Type,Value) ->
- case asn1rt:encode(Module,Type,Value) of
- {ok,X} when is_binary(X) ->
- {ok, binary_to_list(X)};
- {ok,X} ->
- {ok, binary_to_list(list_to_binary(X))};
- Error ->
- Error
- end.
-
-decode(Module, Type, Bytes) when is_binary(Bytes) ->
- asn1rt:decode(Module, Type, Bytes);
-decode(Module, Type, Bytes) when is_list(Bytes) ->
- asn1rt:decode(Module, Type, list_to_binary(Bytes)).
-
-erule(ber) ->
- ber;
-erule(per) ->
- per;
-erule(uper) ->
- per.
-
-
diff --git a/lib/asn1/test/ber_decode_error.erl b/lib/asn1/test/ber_decode_error.erl
index 1c4b4c6894..8be92292ee 100644
--- a/lib/asn1/test/ber_decode_error.erl
+++ b/lib/asn1/test/ber_decode_error.erl
@@ -22,15 +22,15 @@
-export([run/1]).
run([]) ->
- {ok,B} = asn1_wrapper:encode('Constructed','S3',{'S3',17}),
- [T,L|V] = lists:flatten(B),
- Bytes = [T,L+3|V] ++ [2,1,3],
- case asn1_wrapper:decode('Constructed','S3',Bytes) of
+ {ok,B} = 'Constructed':encode('S3', {'S3',17}),
+ [T,L|V] = binary_to_list(B),
+ Bytes = list_to_binary([T,L+3|V] ++ [2,1,3]),
+ case 'Constructed':decode('S3', Bytes) of
{error,{asn1,{unexpected,_}}} -> ok
end,
%% Unexpected bytes must be accepted if there is an extensionmark
- {ok,{'S3ext',17}} = asn1_wrapper:decode('Constructed','S3ext',Bytes),
+ {ok,{'S3ext',17}} = 'Constructed':decode('S3ext', Bytes),
%% Truncated tag.
{error,{asn1,{invalid_tag,_}}} =
diff --git a/lib/asn1/test/choice_extension.erl b/lib/asn1/test/choice_extension.erl
deleted file mode 100644
index 85e0936ebf..0000000000
--- a/lib/asn1/test/choice_extension.erl
+++ /dev/null
@@ -1,37 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-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%
-%%
-%%
--module(choice_extension).
-
--export([run/0, compile/3]).
-
--include_lib("test_server/include/test_server.hrl").
-
-compile(Config,Rules,Options) ->
-
- ?line DataDir = ?config(data_dir,Config),
- ?line OutDir = ?config(priv_dir,Config),
- ?line true = code:add_patha(?config(priv_dir,Config)),
- ?line ok = asn1ct:compile(DataDir ++ "ChoExtension",[Rules,{outdir,OutDir}]++Options).
-
-run() ->
- Val = {str,"abc"},
- ?line {ok,B} = asn1_wrapper:encode('ChoExtension','ChoExt4',Val),
- ?line {ok,Val} = asn1_wrapper:decode('ChoExtension','ChoExt4',lists:flatten(B)),
- ok.
diff --git a/lib/asn1/test/h323test.erl b/lib/asn1/test/h323test.erl
index 426ae16994..3baaa994ea 100644
--- a/lib/asn1/test/h323test.erl
+++ b/lib/asn1/test/h323test.erl
@@ -26,44 +26,62 @@ run(per) -> run();
run(_Rules) -> ok.
run() ->
- alerting(),
- connect(),
+ roundtrip('H323-UserInformation', alerting_val(), alerting_enc()),
+ roundtrip('H323-UserInformation', connect_val(), connect_enc()),
+ general_string(),
ok.
-dec_alerting() ->
- Cs = "0380060008914a0002020120110000000000000000000000000000000000",
- ByteList = hexstr2bytes(Cs),
- asn1_wrapper:decode('H323-MESSAGES','H323-UserInformation',ByteList).
+alerting_val() ->
+ {'H323-UserInformation',
+ {'H323-UU-PDU',
+ {alerting,
+ {'Alerting-UUIE',
+ {0,0,8,2250,0,2},
+ {'EndpointType',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,
+ asn1_NOVALUE,asn1_NOVALUE,
+ {'TerminalInfo',asn1_NOVALUE},
+ false,false},
+ asn1_NOVALUE,
+ {'CallIdentifier',[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},
+ asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}},
+ asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE},
+ asn1_NOVALUE}.
-enc_alerting(V) ->
- asn1_wrapper:encode('H323-MESSAGES','H323-UserInformation',V).
+alerting_enc() ->
+ "0380060008914a0002020120110000000000000000000000000000000000".
-alerting() ->
- {ok,V} = dec_alerting(),
- {ok,B} = enc_alerting(V),
- ByteList = lists:flatten(B),
- {ok,V} = asn1_wrapper:decode('H323-MESSAGES','H323-UserInformation',ByteList).
+connect_val() ->
+ {'H323-UserInformation',
+ {'H323-UU-PDU',
+ {connect,
+ {'Connect-UUIE',
+ {0,0,8,2250,0,2},
+ {ipAddress,
+ {'TransportAddress_ipAddress',[136,225,41,58],1187}},
+ {'EndpointType',asn1_NOVALUE,
+ {'VendorIdentifier',
+ {'H221NonStandard',181,0,21324},
+ [77,105,99,114,111,115,111,102,116,174,32,78,101,116,
+ 77,101,100,116,105,110,103,174,0],
+ [51,46,48,0]},
+ asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,
+ {'TerminalInfo',asn1_NOVALUE},
+ false,false},
+ [22,137,237,197,191,35,211,17,140,45,0,192,79,75,28,208],
+ {'CallIdentifier',[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]},
+ asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}},
+ asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE},
+ asn1_NOVALUE}.
+connect_enc() ->
+ "02c0060008914a00020088e1293a04a322c0b500534c164d6963726f736f6674ae204e65744d656474696e67ae0003332e3000001689edc5bf23d3118c2d00c04f4b1cd00900110000000000000000000000000000000000".
-dec_connect() ->
- Cs = "02c0060008914a00020088e1293a04a322c0b500534c164d6963726f736f6674ae204e65744d656474696e67ae0003332e3000001689edc5bf23d3118c2d00c04f4b1cd00900110000000000000000000000000000000000",
- ByteList = hexstr2bytes(Cs),
- asn1_wrapper:decode('H323-MESSAGES','H323-UserInformation',ByteList).
+general_string() ->
+ Type = 'MultimediaSystemControlMessage',
+ UI = <<109,64,1,57>>,
+ {ok, _V} = 'MULTIMEDIA-SYSTEM-CONTROL':decode(Type, UI).
-enc_connect(V) ->
- asn1_wrapper:encode('H323-MESSAGES','H323-UserInformation',V).
-
-connect() ->
- {ok,V} = dec_connect(),
- {ok,B} = enc_connect(V),
- ByteList = lists:flatten(B),
- {ok,V} = asn1_wrapper:decode('H323-MESSAGES','H323-UserInformation',ByteList).
-
-hexstr2bytes([D1,D2|T]) ->
- [dig2num(D1)*16+dig2num(D2)|hexstr2bytes(T)];
-hexstr2bytes([]) ->
- [].
-
-dig2num(D) when D >= $0, D =< $9 -> D - $0;
-dig2num(D) when D >= $a, D =< $f -> 10 + D - $a;
-dig2num(D) when D >= $A, D =< $F -> 10 + D - $A.
+roundtrip(T, V, HexString) ->
+ Enc = asn1_test_lib:hex_to_bin(HexString),
+ Enc = asn1_test_lib:roundtrip_enc('H323-MESSAGES', T, V),
+ ok.
diff --git a/lib/asn1/test/pem_performance.erl b/lib/asn1/test/pem_performance.erl
deleted file mode 100644
index 87b8cbd61d..0000000000
--- a/lib/asn1/test/pem_performance.erl
+++ /dev/null
@@ -1,37 +0,0 @@
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 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%
-
--module([cert_pem/0]).
--module([dsa_pem/0]).
-
-cert_pem() ->
- 'OTP-PUB-KEY':decode('Certificate',<<48,130,3,184,48,130,3,33,160,3,2,1,2,2,1,1,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,48,129,131,49,14,48,12,6,3,85,4,3,19,5,111,116,112,67,65,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,30,23,13,48,56,48,49,48,57,48,56,50,57,51,48,90,23,13,49,55,49,49,49,55,48,56,50,57,51,48,90,48,129,132,49,15,48,13,6,3,85,4,3,19,6,99,108,105,101,110,116,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,129,159,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,3,129,141,0,48,129,137,2,129,129,0,245,56,68,254,220,239,193,190,63,221,182,60,67,77,121,163,214,136,137,183,139,8,166,30,100,27,45,17,126,58,15,173,151,218,75,224,148,14,22,164,10,100,186,183,104,175,197,97,96,182,146,150,106,129,140,100,194,106,90,62,133,233,155,46,155,33,101,220,83,193,182,232,240,99,253,249,114,8,159,172,143,77,179,132,229,205,29,110,185,233,224,52,25,149,249,100,80,229,199,125,23,106,146,233,159,26,13,8,161,206,221,43,240,149,42,45,194,190,85,6,235,152,220,219,160,32,144,67,2,3,1,0,1,163,130,1,55,48,130,1,51,48,9,6,3,85,29,19,4,2,48,0,48,11,6,3,85,29,15,4,4,3,2,5,224,48,29,6,3,85,29,14,4,22,4,20,26,59,44,5,72,211,158,214,23,34,30,241,125,27,123,115,93,163,231,120,48,129,179,6,3,85,29,35,4,129,171,48,129,168,128,20,6,171,128,52,58,164,184,118,178,189,157,46,40,229,109,145,222,125,1,155,161,129,140,164,129,137,48,129,134,49,17,48,15,6,3,85,4,3,19,8,101,114,108,97,110,103,67,65,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,11,48,9,6,3,85,4,6,19,2,83,69,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,130,1,1,48,33,6,3,85,29,17,4,26,48,24,129,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,33,6,3,85,29,18,4,26,48,24,129,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,3,129,129,0,93,11,112,227,121,15,121,179,247,135,110,216,17,197,84,18,149,166,147,142,190,178,0,209,190,0,142,233,144,100,194,205,220,182,73,204,108,42,95,23,48,63,4,120,239,42,194,25,184,35,117,107,96,229,18,45,76,122,125,40,171,210,132,50,146,178,160,55,17,35,255,208,114,30,47,55,185,154,155,165,204,180,14,143,20,234,6,234,201,225,72,235,5,87,61,255,250,23,217,1,144,246,98,221,223,102,49,168,177,13,70,241,26,27,254,251,217,14,244,18,242,197,151,50,186,214,15,42>>).
-
-dsa_pem() ->
- 'OTP-PUB-KEY':decode('DSAPrivateKey',<<48,130,1,187,2,1,0,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13,2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135,2,20,89,128,159,14,187,249,182,172,15,88,162,110,211,71,179,209,29,125,217,38>>),
- 'OTP-PUB-KEY':decode('SubjectPublicKeyInfo',<<48,130,1,183,48,130,1,44,6,7,42,134,72,206,56,4,1,48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13,3,129,132,0,2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>),
- 'OTP-PUB-KEY':decode('DSAParams',<<48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13>>),
- 'OTP-PUB-KEY':decode('DSAPublicKey',<<2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>),
- 'OTP-PUB-KEY':encode('DSAParams',{params,{'Dss-Parms',129000451850199666185842362389296595317127259539517666765336291347244303954511451744518587442120964433734460998523119938005801396466878889993179871123036311260456172022864663021425348874648247531097042575063545128239655736096045972718934778583429973433661785691086624069991876932064334822608460064613803976593,1216700114794736143432235288305776850295620488937,104420402274523493329542694749036577763086597934731674202966304958550599470165597750883637440049774107540742087494301536297571301945349213110548764383811017178451900599240379681904765817950545426764751538502808499880604633364255316249231153053427235538288687666086821781456733226598288985591031656134573747213}}),
- 'OTP-PUB-KEY':encode(
- 'SubjectPublicKeyInfo',
- {'SubjectPublicKeyInfo',
- {'AlgorithmIdentifier',
- {1,2,840,10040,4,1},
- <<48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13>>},
- {0,
- <<2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>}}).
diff --git a/lib/asn1/test/testChoExtension.erl b/lib/asn1/test/testChoExtension.erl
index c6a07646c2..e54cbe825b 100644
--- a/lib/asn1/test/testChoExtension.erl
+++ b/lib/asn1/test/testChoExtension.erl
@@ -31,10 +31,7 @@ extension(_Rules) ->
%% A trick to encode with another compatible CHOICE type to test reception
%% extension alternative
- {ok,Bytes2x} = asn1_wrapper:encode('ChoExtension','ChoExt1x',{str,"abc"}),
- {ok,Val2x} =
- asn1_wrapper:decode('ChoExtension','ChoExt1',lists:flatten(Bytes2x)),
- io:format("Choice extension alternative = ~p~n",[Val2x]),
+ roundtrip('ChoExt1x', {str,"abc"}),
roundtrip('ChoExt2', {bool,true}),
roundtrip('ChoExt2', {int,33}),
@@ -51,6 +48,4 @@ extension(_Rules) ->
roundtrip(Type, Value) ->
- {ok,Encoded} = 'ChoExtension':encode(Type, Value),
- {ok,Value} = 'ChoExtension':decode(Type, Encoded),
- ok.
+ asn1_test_lib:roundtrip('ChoExtension', Type, Value).
diff --git a/lib/asn1/test/testChoExternal.erl b/lib/asn1/test/testChoExternal.erl
index 5fdee48add..12abdbb2bc 100644
--- a/lib/asn1/test/testChoExternal.erl
+++ b/lib/asn1/test/testChoExternal.erl
@@ -18,25 +18,11 @@
%%
%%
-module(testChoExternal).
-
-
--export([compile/3]).
-export([external/1]).
-include_lib("test_server/include/test_server.hrl").
-include("External.hrl").
-
-
-compile(Config, Rules, Optimize) ->
- DataDir = ?config(data_dir, Config),
- CaseDir = ?config(case_dir, Config),
- true = code:add_patha(CaseDir),
- ok = asn1ct:compile(DataDir ++ "ChoExternal",
- [Rules, {outdir, CaseDir}] ++ Optimize).
-
-
-
external(_Rules) ->
roundtrip('ChoXCho', {boolCho,true}),
roundtrip('ChoXCho', {intCho,77}),
@@ -59,6 +45,4 @@ external(_Rules) ->
ok.
roundtrip(Type, Value) ->
- {ok,Encoded} = 'ChoExternal':encode(Type, Value),
- {ok,Value} = 'ChoExternal':decode(Type, Encoded),
- ok.
+ asn1_test_lib:roundtrip('ChoExternal', Type, Value).
diff --git a/lib/asn1/test/testChoOptional.erl b/lib/asn1/test/testChoOptional.erl
index cbb8134e51..f5e77cb721 100644
--- a/lib/asn1/test/testChoOptional.erl
+++ b/lib/asn1/test/testChoOptional.erl
@@ -18,83 +18,30 @@
%%
%%
-module(testChoOptional).
+-export([run/0]).
--export([optional/1]).
+-record('Seq1', {bool, int = asn1_NOVALUE, cho = asn1_NOVALUE}).
+-record('Seq2', {int = asn1_NOVALUE, cho = asn1_NOVALUE, bool}).
+-record('Seq3', {cho = asn1_NOVALUE, int = asn1_NOVALUE, bool}).
-%-include("ChoOptional.hrl").
--include_lib("test_server/include/test_server.hrl").
--include("External.hrl").
+run() ->
+ roundtrip('Seq1', #'Seq1'{bool=true,int=asn1_NOVALUE,cho=asn1_NOVALUE}),
+ roundtrip('Seq1', #'Seq1'{bool=true,int=233,cho=asn1_NOVALUE}),
+ roundtrip('Seq1', #'Seq1'{bool=true,int=asn1_NOVALUE,cho={vsCho,"Vs Str"}}),
+ roundtrip('Seq1', #'Seq1'{bool=true,int=asn1_NOVALUE,cho={ocStrCho,"Oct Str"}}),
+ roundtrip('Seq2', #'Seq2'{int=asn1_NOVALUE,cho=asn1_NOVALUE,bool=true}),
+ roundtrip('Seq2', #'Seq2'{int=233,cho=asn1_NOVALUE,bool=true}),
+ roundtrip('Seq2', #'Seq2'{int=asn1_NOVALUE,cho={vsCho,"Vs Str"},bool=true}),
+ roundtrip('Seq2', #'Seq2'{int=asn1_NOVALUE,cho={ocStrCho,"Oct Str"},bool=true}),
+ roundtrip('Seq3', #'Seq3'{cho=asn1_NOVALUE,int=asn1_NOVALUE,bool=true}),
+ roundtrip('Seq3', #'Seq3'{cho=asn1_NOVALUE,int=233,bool=true}),
+ roundtrip('Seq3', #'Seq3'{cho={vsCho,"Vs Str"},int=asn1_NOVALUE,bool=true}),
+ roundtrip('Seq3', #'Seq3'{cho={ocStrCho,"Oct Str"},int=asn1_NOVALUE,bool=true}),
+ ok.
--record('Seq1',{bool, int = asn1_NOVALUE, cho = asn1_NOVALUE}).
--record('Seq2',{int = asn1_NOVALUE, cho = asn1_NOVALUE, bool}).
--record('Seq3',{cho = asn1_NOVALUE, int = asn1_NOVALUE, bool}).
+roundtrip(Type, Value) ->
+ roundtrip('ChoOptional', Type, Value),
+ roundtrip('ChoOptionalImplicitTag', Type, Value).
-optional(_Rules) ->
-
- ?line {ok,Bytes11} = asn1_wrapper:encode('ChoOptional','Seq1',#'Seq1'{bool = true}),
- ?line {ok,{'Seq1',true,asn1_NOVALUE,asn1_NOVALUE}} =
- asn1_wrapper:decode('ChoOptional','Seq1',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('ChoOptional','Seq1',#'Seq1'{bool = true,
- int = 233}),
- ?line {ok,{'Seq1',true,233,asn1_NOVALUE}} =
- asn1_wrapper:decode('ChoOptional','Seq1',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} = asn1_wrapper:encode('ChoOptional','Seq1',#'Seq1'{bool = true,
- cho = {vsCho,"Vs Str"}}),
- ?line {ok,{'Seq1',true,asn1_NOVALUE,{vsCho,"Vs Str"}}} =
- asn1_wrapper:decode('ChoOptional','Seq1',lists:flatten(Bytes13)),
-
- ?line {ok,Bytes14} =
- asn1_wrapper:encode('ChoOptional','Seq1',#'Seq1'{bool = true,
- cho = {ocStrCho,"Oct Str"}}),
- ?line {ok,{'Seq1',true,asn1_NOVALUE,{ocStrCho,"Oct Str"}}} =
- asn1_wrapper:decode('ChoOptional','Seq1',lists:flatten(Bytes14)),
-
-
-
- ?line {ok,Bytes21} = asn1_wrapper:encode('ChoOptional','Seq2',#'Seq2'{bool = true}),
- ?line {ok,{'Seq2',asn1_NOVALUE,asn1_NOVALUE,true}} =
- asn1_wrapper:decode('ChoOptional','Seq2',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('ChoOptional','Seq2',#'Seq2'{bool = true,
- int = 233}),
- ?line {ok,{'Seq2',233,asn1_NOVALUE,true}} =
- asn1_wrapper:decode('ChoOptional','Seq2',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes23} = asn1_wrapper:encode('ChoOptional','Seq2',#'Seq2'{bool = true,
- cho = {vsCho,"Vs Str"}}),
- ?line {ok,{'Seq2',asn1_NOVALUE,{vsCho,"Vs Str"},true}} =
- asn1_wrapper:decode('ChoOptional','Seq2',lists:flatten(Bytes23)),
-
- ?line {ok,Bytes24} =
- asn1_wrapper:encode('ChoOptional','Seq2',#'Seq2'{bool = true,
- cho = {ocStrCho,"Oct Str"}}),
- ?line {ok,{'Seq2',asn1_NOVALUE,{ocStrCho,"Oct Str"},true}} =
- asn1_wrapper:decode('ChoOptional','Seq2',lists:flatten(Bytes24)),
-
-
-
- ?line {ok,Bytes31} = asn1_wrapper:encode('ChoOptional','Seq3',#'Seq3'{bool = true}),
- ?line {ok,{'Seq3',asn1_NOVALUE,asn1_NOVALUE,true}} =
- asn1_wrapper:decode('ChoOptional','Seq3',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} = asn1_wrapper:encode('ChoOptional','Seq3',#'Seq3'{bool = true,
- int = 233}),
- ?line {ok,{'Seq3',asn1_NOVALUE,233,true}} =
- asn1_wrapper:decode('ChoOptional','Seq3',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes33} = asn1_wrapper:encode('ChoOptional','Seq3',#'Seq3'{bool = true,
- cho = {vsCho,"Vs Str"}}),
- ?line {ok,{'Seq3',{vsCho,"Vs Str"},asn1_NOVALUE,true}} =
- asn1_wrapper:decode('ChoOptional','Seq3',lists:flatten(Bytes33)),
-
- ?line {ok,Bytes34} =
- asn1_wrapper:encode('ChoOptional','Seq3',#'Seq3'{bool = true,
- cho = {ocStrCho,"Oct Str"}}),
- ?line {ok,{'Seq3',{ocStrCho,"Oct Str"},asn1_NOVALUE,true}} =
- asn1_wrapper:decode('ChoOptional','Seq3',lists:flatten(Bytes34)),
-
-
-
- ok.
+roundtrip(Mod, Type, Value) ->
+ asn1_test_lib:roundtrip(Mod, Type, Value).
diff --git a/lib/asn1/test/testChoOptionalImplicitTag.erl b/lib/asn1/test/testChoOptionalImplicitTag.erl
deleted file mode 100644
index efe335cabd..0000000000
--- a/lib/asn1/test/testChoOptionalImplicitTag.erl
+++ /dev/null
@@ -1,101 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-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%
-%%
-%%
--module(testChoOptionalImplicitTag).
-
-
--export([optional/1]).
-
-%-include("ChoOptional.hrl").
--include_lib("test_server/include/test_server.hrl").
--include("External.hrl").
-
--record('Seq1',{bool, int = asn1_NOVALUE, cho = asn1_NOVALUE}).
--record('Seq2',{int = asn1_NOVALUE, cho = asn1_NOVALUE, bool}).
--record('Seq3',{cho = asn1_NOVALUE, int = asn1_NOVALUE, bool}).
-
-optional(_Rules) ->
-
- ?line {ok,Bytes11} = asn1_wrapper:encode('ChoOptionalImplicitTag','Seq1',#'Seq1'{bool = true}),
- ?line {ok,{'Seq1',true,asn1_NOVALUE,asn1_NOVALUE}} =
- asn1_wrapper:decode('ChoOptionalImplicitTag','Seq1',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('ChoOptionalImplicitTag','Seq1',#'Seq1'{bool = true,
- int = 233}),
- ?line {ok,{'Seq1',true,233,asn1_NOVALUE}} =
- asn1_wrapper:decode('ChoOptionalImplicitTag','Seq1',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} = asn1_wrapper:encode('ChoOptionalImplicitTag','Seq1',#'Seq1'{bool = true,
- cho = {vsCho,"Vs Str"}}),
- ?line {ok,{'Seq1',true,asn1_NOVALUE,{vsCho,"Vs Str"}}} =
- asn1_wrapper:decode('ChoOptionalImplicitTag','Seq1',lists:flatten(Bytes13)),
-
- ?line {ok,Bytes14} =
- asn1_wrapper:encode('ChoOptionalImplicitTag','Seq1',#'Seq1'{bool = true,
- cho = {ocStrCho,"Oct Str"}}),
- ?line {ok,{'Seq1',true,asn1_NOVALUE,{ocStrCho,"Oct Str"}}} =
- asn1_wrapper:decode('ChoOptionalImplicitTag','Seq1',lists:flatten(Bytes14)),
-
-
-
- ?line {ok,Bytes21} = asn1_wrapper:encode('ChoOptionalImplicitTag','Seq2',#'Seq2'{bool = true}),
- ?line {ok,{'Seq2',asn1_NOVALUE,asn1_NOVALUE,true}} =
- asn1_wrapper:decode('ChoOptionalImplicitTag','Seq2',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('ChoOptionalImplicitTag','Seq2',#'Seq2'{bool = true,
- int = 233}),
- ?line {ok,{'Seq2',233,asn1_NOVALUE,true}} =
- asn1_wrapper:decode('ChoOptionalImplicitTag','Seq2',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes23} = asn1_wrapper:encode('ChoOptionalImplicitTag','Seq2',#'Seq2'{bool = true,
- cho = {vsCho,"Vs Str"}}),
- ?line {ok,{'Seq2',asn1_NOVALUE,{vsCho,"Vs Str"},true}} =
- asn1_wrapper:decode('ChoOptionalImplicitTag','Seq2',lists:flatten(Bytes23)),
-
- ?line {ok,Bytes24} =
- asn1_wrapper:encode('ChoOptionalImplicitTag','Seq2',#'Seq2'{bool = true,
- cho = {ocStrCho,"Oct Str"}}),
- ?line {ok,{'Seq2',asn1_NOVALUE,{ocStrCho,"Oct Str"},true}} =
- asn1_wrapper:decode('ChoOptionalImplicitTag','Seq2',lists:flatten(Bytes24)),
-
-
-
- ?line {ok,Bytes31} = asn1_wrapper:encode('ChoOptionalImplicitTag','Seq3',#'Seq3'{bool = true}),
- ?line {ok,{'Seq3',asn1_NOVALUE,asn1_NOVALUE,true}} =
- asn1_wrapper:decode('ChoOptionalImplicitTag','Seq3',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} = asn1_wrapper:encode('ChoOptionalImplicitTag','Seq3',#'Seq3'{bool = true,
- int = 233}),
- ?line {ok,{'Seq3',asn1_NOVALUE,233,true}} =
- asn1_wrapper:decode('ChoOptionalImplicitTag','Seq3',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes33} = asn1_wrapper:encode('ChoOptionalImplicitTag','Seq3',#'Seq3'{bool = true,
- cho = {vsCho,"Vs Str"}}),
- ?line {ok,{'Seq3',{vsCho,"Vs Str"},asn1_NOVALUE,true}} =
- asn1_wrapper:decode('ChoOptionalImplicitTag','Seq3',lists:flatten(Bytes33)),
-
- ?line {ok,Bytes34} =
- asn1_wrapper:encode('ChoOptionalImplicitTag','Seq3',#'Seq3'{bool = true,
- cho = {ocStrCho,"Oct Str"}}),
- ?line {ok,{'Seq3',{ocStrCho,"Oct Str"},asn1_NOVALUE,true}} =
- asn1_wrapper:decode('ChoOptionalImplicitTag','Seq3',lists:flatten(Bytes34)),
-
-
-
- ok.
diff --git a/lib/asn1/test/testChoPrim.erl b/lib/asn1/test/testChoPrim.erl
index 936a38f76c..4665de6989 100644
--- a/lib/asn1/test/testChoPrim.erl
+++ b/lib/asn1/test/testChoPrim.erl
@@ -25,80 +25,44 @@
-include_lib("test_server/include/test_server.hrl").
bool(Rules) ->
-
- ?line {ok,Bytes11} = asn1_wrapper:encode('ChoPrim','ChoCon',{bool0,true}),
- ?line {ok,{bool0,true}} = asn1_wrapper:decode('ChoPrim','ChoCon',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('ChoPrim','ChoCon',{bool1,true}),
- ?line {ok,{bool1,true}} = asn1_wrapper:decode('ChoPrim','ChoCon',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} = asn1_wrapper:encode('ChoPrim','ChoCon',{int2,233}),
- ?line {ok,{int2,233}} = asn1_wrapper:decode('ChoPrim','ChoCon',lists:flatten(Bytes13)),
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {error,{asn1,{invalid_choice_type,wrong}}} =
- case catch asn1_wrapper:encode('ChoPrim','ChoCon',{wrong,233}) of
- X1 -> X1 end,
- ?line {error,{asn1,{invalid_choice_tag,_WrongTag}}} =
- case catch asn1_wrapper:decode('ChoPrim','ChoCon',[131,2,0,233]) of
- X2 -> X2 end,
- ok;
-
- per ->
- ok
- end,
-
+ roundtrip('ChoCon', {bool0,true}),
+ roundtrip('ChoCon', {bool1,true}),
+ roundtrip('ChoCon', {int2,233}),
+ case Rules of
+ ber ->
+ {error,{asn1,{invalid_choice_type,wrong}}} =
+ (catch 'ChoPrim':encode('ChoCon', {wrong,233})),
+ {error,{asn1,{invalid_choice_tag,_WrongTag}}} =
+ (catch 'ChoPrim':decode('ChoCon', <<131,2,0,233>>));
+ per ->
+ ok;
+ uper ->
+ ok
+ end,
ok.
-
-
int(Rules) ->
-
- ?line {ok,Bytes21} = asn1_wrapper:encode('ChoPrim','ChoExp',{int10,1}),
- ?line {ok,{int10,first}} = asn1_wrapper:decode('ChoPrim','ChoExp',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('ChoPrim','ChoExp',{int10,first}),
- ?line {ok,{int10,first}} = asn1_wrapper:decode('ChoPrim','ChoExp',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes23} = asn1_wrapper:encode('ChoPrim','ChoExp',{int10,last}),
- ?line {ok,{int10,last}} = asn1_wrapper:decode('ChoPrim','ChoExp',lists:flatten(Bytes23)),
-
- ?line {ok,Bytes24} = asn1_wrapper:encode('ChoPrim','ChoExp',{bool11,true}),
- ?line {ok,{bool11,true}} = asn1_wrapper:decode('ChoPrim','ChoExp',lists:flatten(Bytes24)),
-
-
- ?line {ok,Bytes26} = asn1_wrapper:encode('ChoPrim','ChoExp',{enum12,one}),
- ?line {ok,{enum12,one}} = asn1_wrapper:decode('ChoPrim','ChoExp',lists:flatten(Bytes26)),
-
- ?line {ok,Bytes25} = asn1_wrapper:encode('ChoPrim','ChoExp',{bool11,true}),
- ?line {ok,{bool11,true}} =
- asn1_wrapper:decode('ChoPrim','ChoExp',lists:flatten(Bytes25)),
-
- ?line {error,{asn1,_}} =
- case catch asn1_wrapper:encode('ChoPrim','ChoExp',{enum12,four}) of
- X3 -> X3 end,
-
- ?line {error,{asn1,_}} =
- case catch asn1_wrapper:encode('ChoPrim','ChoExp',{wrong,233}) of
- X4 -> io:format("error reason = ~p~n",[X4]), X4 end,
-
- ?line case asn1_wrapper:erule(Rules) of
- ber ->
- ?line {error,{asn1,_}} =
- case catch asn1_wrapper:decode('ChoPrim','ChoExp',[107,3,2,1,1]) of
- X5 -> X5 end,
- ok;
-
- per ->
- ok
- end,
+ roundtrip('ChoExp', {int10,1}, {int10,first}),
+ roundtrip('ChoExp', {int10,first}),
+ roundtrip('ChoExp', {int10,last}),
+ roundtrip('ChoExp', {bool11,true}),
+ roundtrip('ChoExp', {enum12,one}),
+ roundtrip('ChoExp', {bool11,true}),
+
+ {error,{asn1,_}} = (catch 'ChoPrim':encode('ChoExp', {enum12,four})),
+ {error,{asn1,_}} = (catch 'ChoPrim':encode('ChoExp', {wrong,233})),
+ case Rules of
+ ber ->
+ {error,{asn1,_}} = (catch 'ChoPrim':decode('ChoExp', <<107,3,2,1,1>>));
+ per ->
+ ok;
+ uper ->
+ ok
+ end,
ok.
+roundtrip(Type, Value) ->
+ roundtrip(Type, Value, Value).
-
-
-
-
-
-
+roundtrip(Type, Value, ExpectedValue) ->
+ asn1_test_lib:roundtrip('ChoPrim', Type, Value, ExpectedValue).
diff --git a/lib/asn1/test/testChoRecursive.erl b/lib/asn1/test/testChoRecursive.erl
index ee26d124a9..593b845949 100644
--- a/lib/asn1/test/testChoRecursive.erl
+++ b/lib/asn1/test/testChoRecursive.erl
@@ -43,6 +43,4 @@ recursive(_Rules) ->
ok.
roundtrip(Type, Value) ->
- {ok,Encoded} = 'ChoRecursive':encode(Type, Value),
- {ok,Value} = 'ChoRecursive':decode(Type, Encoded),
- ok.
+ asn1_test_lib:roundtrip('ChoRecursive', Type, Value).
diff --git a/lib/asn1/test/testChoTypeRefCho.erl b/lib/asn1/test/testChoTypeRefCho.erl
index 9bd732f462..cd2672add0 100644
--- a/lib/asn1/test/testChoTypeRefCho.erl
+++ b/lib/asn1/test/testChoTypeRefCho.erl
@@ -24,43 +24,15 @@
-include_lib("test_server/include/test_server.hrl").
choice(_Rules) ->
-
- ?line {ok,Bytes11} = asn1_wrapper:encode('ChoTypeRefCho','ChoTRcho',{choCho,{choInt,88}}),
- ?line {ok,{choCho,{choInt,88}}} =
- asn1_wrapper:decode('ChoTypeRefCho','ChoTRcho',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('ChoTypeRefCho','ChoTRcho',{choChoE,{choInt,88}}),
- ?line {ok,{choChoE,{choInt,88}}} =
- asn1_wrapper:decode('ChoTypeRefCho','ChoTRcho',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} = asn1_wrapper:encode('ChoTypeRefCho','ChoTRcho',{'choCho-E',{choInt,88}}),
- ?line {ok,{'choCho-E',{choInt,88}}} =
- asn1_wrapper:decode('ChoTypeRefCho','ChoTRcho',lists:flatten(Bytes13)),
-
- ?line {ok,Bytes14} = asn1_wrapper:encode('ChoTypeRefCho','ChoTRcho',{'choChoE-E',{choInt,88}}),
- ?line {ok,{'choChoE-E',{choInt,88}}} =
- asn1_wrapper:decode('ChoTypeRefCho','ChoTRcho',lists:flatten(Bytes14)),
-
-
-
- ?line {ok,Bytes21} = asn1_wrapper:encode('ChoTypeRefCho','ChoChoInline',{bool1,true}),
- ?line {ok,{bool1,true}} =
- asn1_wrapper:decode('ChoTypeRefCho','ChoChoInline',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('ChoTypeRefCho','ChoChoInline',{'choCho',{bool,true}}),
- ?line {ok,{'choCho',{bool,true}}} =
- asn1_wrapper:decode('ChoTypeRefCho','ChoChoInline',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes23} = asn1_wrapper:encode('ChoTypeRefCho','ChoChoInline',{'choCho',{octStr,"kk"}}),
- ?line {ok,{'choCho',{octStr,"kk"}}} =
- asn1_wrapper:decode('ChoTypeRefCho','ChoChoInline',lists:flatten(Bytes23)),
-
- ?line {ok,Bytes24} = asn1_wrapper:encode('ChoTypeRefCho','ChoChoInline',{'choCho',{int,55}}),
- ?line {ok,{'choCho',{int,55}}} =
- asn1_wrapper:decode('ChoTypeRefCho','ChoChoInline',lists:flatten(Bytes24)),
-
-
-
-
-
+ roundtrip('ChoTRcho', {choCho,{choInt,88}}),
+ roundtrip('ChoTRcho', {choChoE,{choInt,88}}),
+ roundtrip('ChoTRcho', {'choCho-E',{choInt,88}}),
+ roundtrip('ChoTRcho', {'choChoE-E',{choInt,88}}),
+ roundtrip('ChoChoInline', {bool1,true}),
+ roundtrip('ChoChoInline', {choCho,{bool,true}}),
+ roundtrip('ChoChoInline', {choCho,{octStr,"kk"}}),
+ roundtrip('ChoChoInline', {choCho,{int,55}}),
ok.
+
+roundtrip(Type, Value) ->
+ asn1_test_lib:roundtrip('ChoTypeRefCho', Type, Value).
diff --git a/lib/asn1/test/testChoTypeRefPrim.erl b/lib/asn1/test/testChoTypeRefPrim.erl
index edef6192fe..8a2bc7bd8e 100644
--- a/lib/asn1/test/testChoTypeRefPrim.erl
+++ b/lib/asn1/test/testChoTypeRefPrim.erl
@@ -24,60 +24,20 @@
-include_lib("test_server/include/test_server.hrl").
prim(_Rules) ->
-
- ?line {ok,Bytes11} = asn1_wrapper:encode('ChoTypeRefPrim','ChoTR',{bool,true}),
- ?line {ok,{bool,true}} = asn1_wrapper:decode('ChoTypeRefPrim','ChoTR',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('ChoTypeRefPrim','ChoTR',{octStr,[11,12,13,14,15,16,17]}),
- ?line {ok,{octStr,[11,12,13,14,15,16,17]}} =
- asn1_wrapper:decode('ChoTypeRefPrim','ChoTR',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} = asn1_wrapper:encode('ChoTypeRefPrim','ChoTR',{int,233}),
- ?line {ok,{int,233}} = asn1_wrapper:decode('ChoTypeRefPrim','ChoTR',lists:flatten(Bytes13)),
-
- ?line {ok,Bytes14} =
- asn1_wrapper:encode('ChoTypeRefPrim','ChoTR',{octStr,"Stringing in the rain"}),
- ?line {ok,{octStr,"Stringing in the rain"}} =
- asn1_wrapper:decode('ChoTypeRefPrim','ChoTR',lists:flatten(Bytes14)),
-
-
-
- ?line {ok,Bytes21} = asn1_wrapper:encode('ChoTypeRefPrim','ChoTR2',{'octStr',"A string"}),
- ?line {ok,{'octStr',"A string"}} =
- asn1_wrapper:decode('ChoTypeRefPrim','ChoTR2',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('ChoTypeRefPrim','ChoTR2',{'octStrI',"A string"}),
- ?line {ok,{'octStrI',"A string"}} =
- asn1_wrapper:decode('ChoTypeRefPrim','ChoTR2',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes23} = asn1_wrapper:encode('ChoTypeRefPrim','ChoTR2',{'octStrE',"A string"}),
- ?line {ok,{'octStrE',"A string"}} =
- asn1_wrapper:decode('ChoTypeRefPrim','ChoTR2',lists:flatten(Bytes23)),
-
- ?line {ok,Bytes24} = asn1_wrapper:encode('ChoTypeRefPrim','ChoTR2',{'octStr-I',"A string"}),
- ?line {ok,{'octStr-I',"A string"}} =
- asn1_wrapper:decode('ChoTypeRefPrim','ChoTR2',lists:flatten(Bytes24)),
-
- ?line {ok,Bytes25} = asn1_wrapper:encode('ChoTypeRefPrim','ChoTR2',{'octStrI-I',"A string"}),
- ?line {ok,{'octStrI-I',"A string"}} =
- asn1_wrapper:decode('ChoTypeRefPrim','ChoTR2',lists:flatten(Bytes25)),
-
- ?line {ok,Bytes26} = asn1_wrapper:encode('ChoTypeRefPrim','ChoTR2',{'octStrE-I',"A string"}),
- ?line {ok,{'octStrE-I',"A string"}} =
- asn1_wrapper:decode('ChoTypeRefPrim','ChoTR2',lists:flatten(Bytes26)),
-
- ?line {ok,Bytes27} = asn1_wrapper:encode('ChoTypeRefPrim','ChoTR2',{'octStr-E',"A string"}),
- ?line {ok,{'octStr-E',"A string"}} =
- asn1_wrapper:decode('ChoTypeRefPrim','ChoTR2',lists:flatten(Bytes27)),
-
- ?line {ok,Bytes28} = asn1_wrapper:encode('ChoTypeRefPrim','ChoTR2',{'octStrI-E',"A string"}),
- ?line {ok,{'octStrI-E',"A string"}} =
- asn1_wrapper:decode('ChoTypeRefPrim','ChoTR2',lists:flatten(Bytes28)),
-
- ?line {ok,Bytes29} = asn1_wrapper:encode('ChoTypeRefPrim','ChoTR2',{'octStrE-E',"A string"}),
- ?line {ok,{'octStrE-E',"A string"}} =
- asn1_wrapper:decode('ChoTypeRefPrim','ChoTR2',lists:flatten(Bytes29)),
-
-
+ roundtrip('ChoTR', {bool,true}),
+ roundtrip('ChoTR', {octStr,[11,12,13,14,15,16,17]}),
+ roundtrip('ChoTR', {int,233}),
+ roundtrip('ChoTR', {octStr,"Stringing in the rain"}),
+ roundtrip('ChoTR2', {octStr,"A string"}),
+ roundtrip('ChoTR2', {octStrI,"A string"}),
+ roundtrip('ChoTR2', {octStrE,"A string"}),
+ roundtrip('ChoTR2', {'octStr-I',"A string"}),
+ roundtrip('ChoTR2', {'octStrI-I',"A string"}),
+ roundtrip('ChoTR2', {'octStrE-I',"A string"}),
+ roundtrip('ChoTR2', {'octStr-E',"A string"}),
+ roundtrip('ChoTR2', {'octStrI-E',"A string"}),
+ roundtrip('ChoTR2', {'octStrE-E',"A string"}),
ok.
+
+roundtrip(Type, Value) ->
+ asn1_test_lib:roundtrip('ChoTypeRefPrim', Type, Value).
diff --git a/lib/asn1/test/testChoTypeRefSeq.erl b/lib/asn1/test/testChoTypeRefSeq.erl
index bf2b66c73e..86c22619aa 100644
--- a/lib/asn1/test/testChoTypeRefSeq.erl
+++ b/lib/asn1/test/testChoTypeRefSeq.erl
@@ -23,82 +23,21 @@
-include_lib("test_server/include/test_server.hrl").
--record('ChoSeq',{seqInt, seqOs}).
--record('ChoSeqImp',{seqInt, seqOs}).
--record('ChoSeqExp',{seqInt, seqOs}).
+-record('ChoSeq', {seqInt, seqOs}).
+-record('ChoSeqImp', {seqInt, seqOs}).
+-record('ChoSeqExp', {seqInt, seqOs}).
seq(_Rules) ->
-
- ?line {ok,Bytes1} =
- asn1_wrapper:encode('ChoTypeRefSeq','ChoTRseq',
- {choSeq,#'ChoSeq'{seqInt = 88,
- seqOs = "A string"}}),
- ?line {ok,{choSeq,{'ChoSeq',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSeq','ChoTRseq',lists:flatten(Bytes1)),
-
-
- ?line {ok,Bytes2} =
- asn1_wrapper:encode('ChoTypeRefSeq','ChoTRseq',
- {choSeqI,#'ChoSeq'{seqInt = 88,
- seqOs = "A string"}}),
- ?line {ok,{choSeqI,{'ChoSeq',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSeq','ChoTRseq',lists:flatten(Bytes2)),
-
-
- ?line {ok,Bytes3} =
- asn1_wrapper:encode('ChoTypeRefSeq','ChoTRseq',
- {choSeqE,#'ChoSeq'{seqInt = 88,
- seqOs = "A string"}}),
- ?line {ok,{choSeqE,{'ChoSeq',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSeq','ChoTRseq',lists:flatten(Bytes3)),
-
-
- ?line {ok,Bytes4} =
- asn1_wrapper:encode('ChoTypeRefSeq','ChoTRseq',
- {'choSeq-I',#'ChoSeqImp'{seqInt = 88,
- seqOs = "A string"}}),
- ?line {ok,{'choSeq-I',{'ChoSeqImp',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSeq','ChoTRseq',lists:flatten(Bytes4)),
-
-
- ?line {ok,Bytes5} =
- asn1_wrapper:encode('ChoTypeRefSeq','ChoTRseq',
- {'choSeqI-I',#'ChoSeqImp'{seqInt = 88,
- seqOs = "A string"}}),
- ?line {ok,{'choSeqI-I',{'ChoSeqImp',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSeq','ChoTRseq',lists:flatten(Bytes5)),
-
-
- ?line {ok,Bytes6} =
- asn1_wrapper:encode('ChoTypeRefSeq','ChoTRseq',
- {'choSeqE-I',#'ChoSeqImp'{seqInt = 88,
- seqOs = "A string"}}),
- ?line {ok,{'choSeqE-I',{'ChoSeqImp',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSeq','ChoTRseq',lists:flatten(Bytes6)),
-
-
- ?line {ok,Bytes7} =
- asn1_wrapper:encode('ChoTypeRefSeq','ChoTRseq',
- {'choSeq-E',#'ChoSeqExp'{seqInt = 88,
- seqOs = "A string"}}),
- ?line {ok,{'choSeq-E',{'ChoSeqExp',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSeq','ChoTRseq',lists:flatten(Bytes7)),
-
-
- ?line {ok,Bytes8} =
- asn1_wrapper:encode('ChoTypeRefSeq','ChoTRseq',
- {'choSeqI-E',#'ChoSeqExp'{seqInt = 88,
- seqOs = "A string"}}),
- ?line {ok,{'choSeqI-E',{'ChoSeqExp',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSeq','ChoTRseq',lists:flatten(Bytes8)),
-
-
- ?line {ok,Bytes9} =
- asn1_wrapper:encode('ChoTypeRefSeq','ChoTRseq',
- {'choSeqE-E',#'ChoSeqExp'{seqInt = 88,
- seqOs = "A string"}}),
- ?line {ok,{'choSeqE-E',{'ChoSeqExp',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSeq','ChoTRseq',lists:flatten(Bytes9)),
-
-
+ roundtrip('ChoTRseq', {choSeq,#'ChoSeq'{seqInt=88,seqOs="A string"}}),
+ roundtrip('ChoTRseq', {choSeqI,#'ChoSeq'{seqInt=88,seqOs="A string"}}),
+ roundtrip('ChoTRseq', {choSeqE,#'ChoSeq'{seqInt=88,seqOs="A string"}}),
+ roundtrip('ChoTRseq', {'choSeq-I',#'ChoSeqImp'{seqInt=88,seqOs="A string"}}),
+ roundtrip('ChoTRseq', {'choSeqI-I',#'ChoSeqImp'{seqInt=88,seqOs="A string"}}),
+ roundtrip('ChoTRseq', {'choSeqE-I',#'ChoSeqImp'{seqInt=88,seqOs="A string"}}),
+ roundtrip('ChoTRseq', {'choSeq-E',#'ChoSeqExp'{seqInt=88,seqOs="A string"}}),
+ roundtrip('ChoTRseq', {'choSeqI-E',#'ChoSeqExp'{seqInt=88,seqOs="A string"}}),
+ roundtrip('ChoTRseq', {'choSeqE-E',#'ChoSeqExp'{seqInt=88,seqOs="A string"}}),
ok.
+
+roundtrip(Type, Value) ->
+ asn1_test_lib:roundtrip('ChoTypeRefSeq', Type, Value).
diff --git a/lib/asn1/test/testChoTypeRefSet.erl b/lib/asn1/test/testChoTypeRefSet.erl
index 8a3e8bdbb0..fd3d75cbcb 100644
--- a/lib/asn1/test/testChoTypeRefSet.erl
+++ b/lib/asn1/test/testChoTypeRefSet.erl
@@ -23,83 +23,21 @@
-include_lib("test_server/include/test_server.hrl").
--record('ChoSet',{setInt, setOs}).
--record('ChoSetImp',{setInt, setOs}).
--record('ChoSetExp',{setInt, setOs}).
+-record('ChoSet', {setInt, setOs}).
+-record('ChoSetImp', {setInt, setOs}).
+-record('ChoSetExp', {setInt, setOs}).
set(_Rules) ->
-
- ?line {ok,Bytes1} =
- asn1_wrapper:encode('ChoTypeRefSet','ChoTRset',
- {choSet,#'ChoSet'{setInt = 88,
- setOs = "A string"}}),
- ?line {ok,{choSet,{'ChoSet',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSet','ChoTRset',lists:flatten(Bytes1)),
-
-
- ?line {ok,Bytes2} =
- asn1_wrapper:encode('ChoTypeRefSet','ChoTRset',
- {choSetI,#'ChoSet'{setInt = 88,
- setOs = "A string"}}),
- ?line {ok,{choSetI,{'ChoSet',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSet','ChoTRset',lists:flatten(Bytes2)),
-
-
- ?line {ok,Bytes3} =
- asn1_wrapper:encode('ChoTypeRefSet','ChoTRset',
- {choSetE,#'ChoSet'{setInt = 88,
- setOs = "A string"}}),
- ?line {ok,{choSetE,{'ChoSet',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSet','ChoTRset',lists:flatten(Bytes3)),
-
-
- ?line {ok,Bytes4} =
- asn1_wrapper:encode('ChoTypeRefSet','ChoTRset',
- {'choSet-I',#'ChoSetImp'{setInt = 88,
- setOs = "A string"}}),
- ?line {ok,{'choSet-I',{'ChoSetImp',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSet','ChoTRset',lists:flatten(Bytes4)),
-
-
- ?line {ok,Bytes5} =
- asn1_wrapper:encode('ChoTypeRefSet','ChoTRset',
- {'choSetI-I',#'ChoSetImp'{setInt = 88,
- setOs = "A string"}}),
- ?line {ok,{'choSetI-I',{'ChoSetImp',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSet','ChoTRset',lists:flatten(Bytes5)),
-
-
- ?line {ok,Bytes6} =
- asn1_wrapper:encode('ChoTypeRefSet','ChoTRset',
- {'choSetE-I',#'ChoSetImp'{setInt = 88,
- setOs = "A string"}}),
- ?line {ok,{'choSetE-I',{'ChoSetImp',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSet','ChoTRset',lists:flatten(Bytes6)),
-
-
- ?line {ok,Bytes7} =
- asn1_wrapper:encode('ChoTypeRefSet','ChoTRset',
- {'choSet-E',#'ChoSetExp'{setInt = 88,
- setOs = "A string"}}),
- ?line {ok,{'choSet-E',{'ChoSetExp',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSet','ChoTRset',lists:flatten(Bytes7)),
-
-
- ?line {ok,Bytes8} =
- asn1_wrapper:encode('ChoTypeRefSet','ChoTRset',
- {'choSetI-E',#'ChoSetExp'{setInt = 88,
- setOs = "A string"}}),
- ?line {ok,{'choSetI-E',{'ChoSetExp',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSet','ChoTRset',lists:flatten(Bytes8)),
-
-
- ?line {ok,Bytes9} =
- asn1_wrapper:encode('ChoTypeRefSet','ChoTRset',
- {'choSetE-E',#'ChoSetExp'{setInt = 88,
- setOs = "A string"}}),
- ?line {ok,{'choSetE-E',{'ChoSetExp',88,"A string"}}} =
- asn1_wrapper:decode('ChoTypeRefSet','ChoTRset',lists:flatten(Bytes9)),
-
-
-
+ roundtrip('ChoTRset', {choSet,#'ChoSet'{setInt=88,setOs="A string"}}),
+ roundtrip('ChoTRset', {choSetI,#'ChoSet'{setInt=88,setOs="A string"}}),
+ roundtrip('ChoTRset', {choSetE,#'ChoSet'{setInt=88,setOs="A string"}}),
+ roundtrip('ChoTRset', {'choSet-I',#'ChoSetImp'{setInt=88,setOs="A string"}}),
+ roundtrip('ChoTRset', {'choSetI-I',#'ChoSetImp'{setInt=88,setOs="A string"}}),
+ roundtrip('ChoTRset', {'choSetE-I',#'ChoSetImp'{setInt=88,setOs="A string"}}),
+ roundtrip('ChoTRset', {'choSet-E',#'ChoSetExp'{setInt=88,setOs="A string"}}),
+ roundtrip('ChoTRset', {'choSetI-E',#'ChoSetExp'{setInt=88,setOs="A string"}}),
+ roundtrip('ChoTRset', {'choSetE-E',#'ChoSetExp'{setInt=88,setOs="A string"}}),
ok.
+
+roundtrip(Type, Value) ->
+ asn1_test_lib:roundtrip('ChoTypeRefSet', Type, Value).
diff --git a/lib/asn1/test/testChoiceIndefinite.erl b/lib/asn1/test/testChoiceIndefinite.erl
index b5832c985a..87910cf6ec 100644
--- a/lib/asn1/test/testChoiceIndefinite.erl
+++ b/lib/asn1/test/testChoiceIndefinite.erl
@@ -32,6 +32,6 @@ main(ber) ->
Bi = [48,128,160,128,128,1,11,0,0,129,1,12,0,0],
%% the value which is encoded
V = {'Seq',{ca,11},12},
- ?line {ok,V} = asn1_wrapper:decode('ChoiceIndef','Seq',B),
- ?line {ok,V} = asn1_wrapper:decode('ChoiceIndef','Seq',Bi),
+ {ok,V} = 'ChoiceIndef':decode('Seq', B),
+ {ok,V} = 'ChoiceIndef':decode('Seq', Bi),
ok.
diff --git a/lib/asn1/test/testConstraints.erl b/lib/asn1/test/testConstraints.erl
index 03a09492af..34fbbcf6cc 100644
--- a/lib/asn1/test/testConstraints.erl
+++ b/lib/asn1/test/testConstraints.erl
@@ -122,6 +122,42 @@ int_constraints(Rules) ->
range_error(Rules, 'X1', 21),
%%==========================================================
+ %% Union of single values
+ %% Sv1 ::= INTEGER (2|3|17)
+ %% Sv2 ::= INTEGER (2|3|17, ...)
+ %% Sv3 ::= INTEGER {a(2),b(3),z(17)} (2|3|17, ...)
+ %%==========================================================
+
+ range_error(Rules, 'Sv1', 1),
+ range_error(Rules, 'Sv1', 18),
+ roundtrip('Sv1', 2),
+ roundtrip('Sv1', 3),
+ roundtrip('Sv1', 7),
+
+ %% Encoded as root
+ v_roundtrip(Rules, 'Sv2', 2),
+ v_roundtrip(Rules, 'Sv2', 3),
+ v_roundtrip(Rules, 'Sv2', 17),
+
+ %% Encoded as extension
+ v_roundtrip(Rules, 'Sv2', 1),
+ v_roundtrip(Rules, 'Sv2', 4),
+ v_roundtrip(Rules, 'Sv2', 18),
+
+ %% Encoded as root
+ v_roundtrip(Rules, 'Sv3', a),
+ v_roundtrip(Rules, 'Sv3', b),
+ v_roundtrip(Rules, 'Sv3', z),
+ v_roundtrip(Rules, 'Sv3', 2, a),
+ v_roundtrip(Rules, 'Sv3', 3, b),
+ v_roundtrip(Rules, 'Sv3', 17, z),
+
+ %% Encoded as extension
+ v_roundtrip(Rules, 'Sv3', 1),
+ v_roundtrip(Rules, 'Sv3', 4),
+ v_roundtrip(Rules, 'Sv3', 18),
+
+ %%==========================================================
%% SemiConstrained
%%==========================================================
@@ -197,33 +233,54 @@ 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".
+v(uper, 'NegSemiConstrainedExt', 0) -> "00C000";
+v(ber, 'Sv2', 1) -> "020101";
+v(per, 'Sv2', 1) -> "800101";
+v(uper, 'Sv2', 1) -> "808080";
+v(ber, 'Sv2', 2) -> "020102";
+v(per, 'Sv2', 2) -> "00";
+v(uper, 'Sv2', 2) -> "00";
+v(ber, 'Sv2', 3) -> "020103";
+v(per, 'Sv2', 3) -> "08";
+v(uper, 'Sv2', 3) -> "08";
+v(ber, 'Sv2', 4) -> "020104";
+v(per, 'Sv2', 4) -> "800104";
+v(uper, 'Sv2', 4) -> "808200";
+v(ber, 'Sv2', 17) -> "020111";
+v(per, 'Sv2', 17) -> "78";
+v(uper, 'Sv2', 17) -> "78";
+v(ber, 'Sv2', 18) -> "020112";
+v(per, 'Sv2', 18) -> "800112";
+v(uper, 'Sv2', 18) -> "808900";
+v(Rule, 'Sv3', a) -> v(Rule, 'Sv2', 2);
+v(Rule, 'Sv3', b) -> v(Rule, 'Sv2', 3);
+v(Rule, 'Sv3', z) -> v(Rule, 'Sv2', 17);
+v(Rule, 'Sv3', Val) when is_integer(Val) -> v(Rule, 'Sv2', Val).
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).
+ roundtrip('AnotherThing', fred),
+ {error,_Reason} = 'Constraints':encode('AnotherThing', fred3).
v_roundtrip(Erule, Type, Value) ->
Encoded = asn1_test_lib:hex_to_bin(v(Erule, Type, Value)),
Encoded = roundtrip('Constraints', Type, Value).
+v_roundtrip(Erule, Type, Value, Expected) ->
+ Encoded = asn1_test_lib:hex_to_bin(v(Erule, Type, Value)),
+ Encoded = asn1_test_lib:roundtrip_enc('Constraints', Type, Value, Expected).
+
roundtrip(Type, Value) ->
roundtrip('Constraints', Type, Value).
roundtrip(Module, Type, Value) ->
- {ok,Encoded} = Module:encode(Type, Value),
- {ok,Value} = Module:decode(Type, Encoded),
- Encoded.
+ asn1_test_lib:roundtrip_enc(Module, Type, Value).
roundtrip_enc(Type, Value, Enc) ->
- Module = 'Constraints',
- {ok,Encoded} = Module:encode(Type, Value),
- {ok,Value} = Module:decode(Type, Encoded),
+ Encoded = asn1_test_lib:roundtrip_enc('Constraints', Type, Value),
case Enc of
none -> ok;
Encoded -> ok
diff --git a/lib/asn1/test/testContextSwitchingTypes.erl b/lib/asn1/test/testContextSwitchingTypes.erl
index 40dbe25015..bdd6883dac 100644
--- a/lib/asn1/test/testContextSwitchingTypes.erl
+++ b/lib/asn1/test/testContextSwitchingTypes.erl
@@ -24,31 +24,21 @@
-include_lib("test_server/include/test_server.hrl").
test(Config) ->
- ?line ValT = 'ContextSwitchingTypes':'val1-T'(),
- ?line {ok,Bytes1} =
- asn1_wrapper:encode('ContextSwitchingTypes','T',ValT),
- ?line {ok,Result1} =
- asn1_wrapper:decode('ContextSwitchingTypes','T',Bytes1),
- ?line ok = check_EXTERNAL(Result1),
- ?line {ok,ValT2} = asn1ct:value('ContextSwitchingTypes','T',
- [{i, ?config(case_dir, Config)}]),
- ?line {ok,Bytes1_2} =
- asn1_wrapper:encode('ContextSwitchingTypes','T',ValT2),
- ?line {ok,Result1_2} =
- asn1_wrapper:decode('ContextSwitchingTypes','T',Bytes1_2),
- ?line ok = check_EXTERNAL(Result1_2),
+ ValT = 'ContextSwitchingTypes':'val1-T'(),
+ check_EXTERNAL(enc_dec('T', ValT)),
- ?line ValEP = 'ContextSwitchingTypes':'val1-EP'(),
- ?line {ok,Bytes2} =
- asn1_wrapper:encode('ContextSwitchingTypes','EP',ValEP),
- ?line {ok,_Result2} =
- asn1_wrapper:decode('ContextSwitchingTypes','EP',Bytes2),
+ {ok,ValT2} = asn1ct:value('ContextSwitchingTypes', 'T',
+ [{i,?config(case_dir, Config)}]),
+ check_EXTERNAL(enc_dec('T', ValT2)),
- ?line ValCS = 'ContextSwitchingTypes':'val1-CS'(),
- ?line {ok,Bytes3} =
- asn1_wrapper:encode('ContextSwitchingTypes','CS',ValCS),
- ?line {ok,_Result3} =
- asn1_wrapper:decode('ContextSwitchingTypes','CS',Bytes3).
+ ValEP = 'ContextSwitchingTypes':'val1-EP'(),
+ ValEPDec = enc_dec('EP', ValEP),
+ io:format("~p\n~p\n", [ValEP,ValEPDec]),
+
+ ValCS = 'ContextSwitchingTypes':'val1-CS'(),
+ ValCSDec = enc_dec('EP', ValCS),
+ io:format("~p\n~p\n", [ValCS,ValCSDec]),
+ ok.
check_EXTERNAL({'EXTERNAL',Identif,DVD,DV})->
@@ -85,3 +75,9 @@ check_object_identifier(Tuple) when is_tuple(Tuple) ->
not is_integer(E)] of
[] -> ok
end.
+
+enc_dec(T, V0) ->
+ M = 'ContextSwitchingTypes',
+ {ok,Enc} = M:encode(T, V0),
+ {ok,V} = M:decode(T, Enc),
+ V.
diff --git a/lib/asn1/test/testDER.erl b/lib/asn1/test/testDER.erl
index 395116bd34..3f74a16797 100644
--- a/lib/asn1/test/testDER.erl
+++ b/lib/asn1/test/testDER.erl
@@ -25,26 +25,24 @@
test() ->
Val = {'Set',12,{version,214},true},
- ?line {ok,Bin}=asn1_wrapper:encode('DERSpec','Set',Val),
- ?line ok = match_value('Set',Bin),
- ?line {ok,{'Set',12,{version,214},true}} =
- asn1_wrapper:decode('DERSpec','Set',Bin),
+ roundtrip_enc('Set', Val, <<49,12,1,1,255,2,2,0,214,161,3,2,1,12>>),
- ValSof = [{version,12},{message,"PrintableString"},{message,"Print"},{version,11}],
- ?line {ok,BSof} = asn1_wrapper:encode('DERSpec','SetOf',ValSof),
- ?line ok = match_value('SetOf',BSof),
- ?line {ok,[{version,11},{version,12},{message,"Print"},{message,"PrintableString"}]} = asn1_wrapper:decode('DERSpec','SetOf',BSof),
+ ValSof = [{version,12},{message,"PrintableString"},
+ {message,"Print"},{version,11}],
+ ValSofSorted = [{version,11},{version,12},
+ {message,"Print"},{message,"PrintableString"}],
+ roundtrip_enc('SetOf', ValSof, ValSofSorted,
+ <<49,30,2,1,11,2,1,12,19,5,80,114,105,110,116,19,15,80,
+ 114,105,110,116,97,98,108,101,83,116,114,105,110,103>>),
ValSO = [{'Seq2',1,true},{'Seq2',120000,false},{'Seq2',3,true}],
- ?line {ok,SOB} = asn1_wrapper:encode('DERSpec','SO',ValSO),
- ?line {ok,ValSO} = asn1_wrapper:decode('DERSpec','SO',SOB).
+ roundtrip('SO', ValSO).
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('DERSpec', T, V).
-match_value('Set',<<49,12,1,1,255,2,2,0,214,161,3,2,1,12>>) ->
- ok;
-match_value('Set',[49,12,1,1,255,2,2,0,214,161,3,2,1,12]) ->
- ok;
-match_value('SetOf',<<49,30,2,1,11,2,1,12,19,5,80,114,105,110,116,19,15,80,114,105,110,116,97,98,108,101,83,116,114,105,110,103>>) -> ok;
-match_value('SetOf',[49,30,2,1,11,2,1,12,19,5,80,114,105,110,116,19,15,80,114,105,110,116,97,98,108,101,83,116,114,105,110,103]) -> ok;
-match_value(_,B) ->
- {error,B}.
+roundtrip_enc(T, V, Enc) ->
+ Enc = asn1_test_lib:roundtrip_enc('DERSpec', T, V).
+
+roundtrip_enc(T, V, Expected, Enc) ->
+ Enc = asn1_test_lib:roundtrip_enc('DERSpec', T, V, Expected).
diff --git a/lib/asn1/test/testDeepTConstr.erl b/lib/asn1/test/testDeepTConstr.erl
index 620b5f3356..880f15e91a 100644
--- a/lib/asn1/test/testDeepTConstr.erl
+++ b/lib/asn1/test/testDeepTConstr.erl
@@ -88,9 +88,7 @@ main(_Erule) ->
roundtrip(M, T, V) ->
- {ok,E} = M:encode(T, V),
- {ok,V} = M:decode(T, E),
- ok.
+ asn1_test_lib:roundtrip(M, T, V).
%% Either encoding or decoding must fail.
must_fail(M, T, V) ->
diff --git a/lib/asn1/test/testDef.erl b/lib/asn1/test/testDef.erl
index 48f0015008..b8df3c4f8b 100644
--- a/lib/asn1/test/testDef.erl
+++ b/lib/asn1/test/testDef.erl
@@ -37,81 +37,45 @@
bool33 = asn1_DEFAULT}).
main(_Rules) ->
-
- ?line {ok,Bytes11} = asn1_wrapper:encode('Def','Def1',#'Def1'{bool0 = true,
- bool1 = true,
- bool2 = true,
- bool3 = true}),
- ?line {ok,{'Def1',true,true,true,true}} =
- asn1_wrapper:decode('Def','Def1',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('Def','Def1',#'Def1'{bool0 = true}),
- ?line {ok,{'Def1',true,false,false,false}} =
- asn1_wrapper:decode('Def','Def1',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} = asn1_wrapper:encode('Def','Def1',#'Def1'{bool0 = true,
- bool2 = false}),
- ?line {ok,{'Def1',true,false,false,false}} =
- asn1_wrapper:decode('Def','Def1',lists:flatten(Bytes13)),
-
- ?line {ok,Bytes14} = asn1_wrapper:encode('Def','Def1',#'Def1'{bool0 = false,
- bool3 = false}),
- ?line {ok,{'Def1',false,false,false,false}} =
- asn1_wrapper:decode('Def','Def1',lists:flatten(Bytes14)),
-
-
-
-
- ?line {ok,Bytes21} = asn1_wrapper:encode('Def','Def2',#'Def2'{bool10 = false,
- bool11 = false,
- bool12 = false,
- bool13 = false}),
- ?line {ok,{'Def2',false,false,false,false}} =
- asn1_wrapper:decode('Def','Def2',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('Def','Def2',#'Def2'{bool10 = true,
- bool13 = false}),
- ?line {ok,{'Def2',true,false,false,false}} =
- asn1_wrapper:decode('Def','Def2',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes23} = asn1_wrapper:encode('Def','Def2',#'Def2'{bool10 = true,
- bool11 = false,
- bool13 = false}),
- ?line {ok,{'Def2',true,false,false,false}} =
- asn1_wrapper:decode('Def','Def2',lists:flatten(Bytes23)),
-
- ?line {ok,Bytes24} = asn1_wrapper:encode('Def','Def2',#'Def2'{bool10 = false,
- bool12 = false,
- bool13 = false}),
- ?line {ok,{'Def2',false,false,false,false}} =
- asn1_wrapper:decode('Def','Def2',lists:flatten(Bytes24)),
-
-
-
-
- ?line {ok,Bytes31} = asn1_wrapper:encode('Def','Def3',#'Def3'{bool30 = false,
- bool31 = false,
- bool32 = false,
- bool33 = false}),
- ?line {ok,{'Def3',false,false,false,false}} =
- asn1_wrapper:decode('Def','Def3',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} = asn1_wrapper:encode('Def','Def3',#'Def3'{}),
- ?line {ok,{'Def3',false,false,false,false}} =
- asn1_wrapper:decode('Def','Def3',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes33} = asn1_wrapper:encode('Def','Def3',#'Def3'{bool30 = true}),
- ?line {ok,{'Def3',true,false,false,false}} =
- asn1_wrapper:decode('Def','Def3',lists:flatten(Bytes33)),
-
- ?line {ok,Bytes34} = asn1_wrapper:encode('Def','Def3',#'Def3'{bool32 = false}),
- ?line {ok,{'Def3',false,false,false,false}} =
- asn1_wrapper:decode('Def','Def3',lists:flatten(Bytes34)),
-
- ?line {ok,Bytes35} = asn1_wrapper:encode('Def','Def3',#'Def3'{bool33 = false}),
- ?line {ok,{'Def3',false,false,false,false}} =
- asn1_wrapper:decode('Def','Def3',lists:flatten(Bytes35)),
-
-
-
+ roundtrip('Def1', #'Def1'{bool0=true,bool1=true,bool2=true,bool3=true}),
+ roundtrip('Def1',
+ #'Def1'{bool0=true},
+ #'Def1'{bool0=true,bool1=false,bool2=false,bool3=false}),
+ roundtrip('Def1',
+ #'Def1'{bool0=true,bool2=false},
+ #'Def1'{bool0=true,bool1=false,bool2=false,bool3=false}),
+ roundtrip('Def1',
+ #'Def1'{bool0=false,bool3=false},
+ #'Def1'{bool0=false,bool1=false,bool2=false,bool3=false}),
+
+ roundtrip('Def2', #'Def2'{bool10=false,bool11=false,bool12=false,bool13=false}),
+ roundtrip('Def2',
+ #'Def2'{bool10=true,bool13=false},
+ #'Def2'{bool10=true,bool11=false,bool12=false,bool13=false}),
+ roundtrip('Def2',
+ #'Def2'{bool10=true,bool11=false,bool13=false},
+ #'Def2'{bool10=true,bool11=false,bool12=false,bool13=false}),
+ roundtrip('Def2',
+ #'Def2'{bool10=false,bool12=false,bool13=false},
+ #'Def2'{bool10=false,bool11=false,bool12=false,bool13=false}),
+
+ roundtrip('Def3', #'Def3'{bool30=false,bool31=false,bool32=false,bool33=false}),
+ roundtrip('Def3',
+ #'Def3'{},
+ #'Def3'{bool30=false,bool31=false,bool32=false,bool33=false}),
+ roundtrip('Def3',
+ #'Def3'{bool30=true},
+ #'Def3'{bool30=true,bool31=false,bool32=false,bool33=false}),
+ roundtrip('Def3',
+ #'Def3'{bool32=false},
+ #'Def3'{bool30=false,bool31=false,bool32=false,bool33=false}),
+ roundtrip('Def3',
+ #'Def3'{bool33=false},
+ #'Def3'{bool30=false,bool31=false,bool32=false,bool33=false}),
ok.
+
+roundtrip(Type, Value) ->
+ roundtrip(Type, Value, Value).
+
+roundtrip(Type, Value, ExpectedValue) ->
+ asn1_test_lib:roundtrip('Def', Type, Value, ExpectedValue).
diff --git a/lib/asn1/test/testDoubleEllipses.erl b/lib/asn1/test/testDoubleEllipses.erl
index 1032156b91..4e8972cdfc 100644
--- a/lib/asn1/test/testDoubleEllipses.erl
+++ b/lib/asn1/test/testDoubleEllipses.erl
@@ -34,67 +34,27 @@
-record('SetAltV2',{a,d,b,e,h,i,c,f,g}).
main(_Rules) ->
- %% SEQUENCE
- ?line {ok,Bytes} =
- asn1_wrapper:encode('DoubleEllipses','Seq',#'Seq'{a = 10,c = true}),
- ?line {ok,#'SeqV2'{a=10,b = asn1_NOVALUE, c = true}} =
- asn1_wrapper:decode('DoubleEllipses','SeqV2',Bytes),
- ?line {ok,Bytes2} =
- asn1_wrapper:encode('DoubleEllipses','SeqV2',
- #'SeqV2'{a=10,b = false, c = true}),
- ?line {ok,#'Seq'{a = 10, c = true}} =
- asn1_wrapper:decode('DoubleEllipses','Seq',Bytes2),
+ roundtrip('Seq', #'Seq'{a=10,c=true}),
+ roundtrip('SeqV2', #'SeqV2'{a=10,b=false,c=true}),
+ roundtrip('SeqAlt',
+ #'SeqAlt'{a=10,d=12,b = <<2#1010:4>>,
+ e=true,c=false,f=14,g=16}),
+ roundtrip('SeqAltV2',
+ #'SeqAltV2'{a=10,d=12,
+ b = <<2#1010:4>>,
+ e=true,h="PS",i=13,c=false,f=14,g=16}),
- ?line {ok,Bytes3} =
- asn1_wrapper:encode('DoubleEllipses','SeqAlt',
- #'SeqAlt'{a = 10, d = 12,
- b = [1,0,1,0], e = true,
- c = false, f = 14, g = 16}),
- ?line {ok,#'SeqAltV2'{a = 10, d = 12,
- b = <<2#1010:4>>, e = true,
- h = asn1_NOVALUE, i = asn1_NOVALUE,
- c = false, f = 14, g = 16}} =
- asn1_wrapper:decode('DoubleEllipses','SeqAltV2',Bytes3),
- ?line {ok,Bytes4} =
- asn1_wrapper:encode('DoubleEllipses','SeqAltV2',
- #'SeqAltV2'{a = 10, d = 12,
- b = [1,0,1,0], e = true,
- h = "PS", i = 13,
- c = false, f = 14, g = 16}),
- ?line {ok,#'SeqAlt'{a = 10, d = 12,
- b = <<2#1010:4>>, e = true,
- c = false, f = 14, g = 16}} =
- asn1_wrapper:decode('DoubleEllipses','SeqAlt',Bytes4),
-
- %% SET
- ?line {ok,Bytes5} =
- asn1_wrapper:encode('DoubleEllipses','Set',#'Set'{a = 10,c = true}),
- ?line {ok,#'SetV2'{a=10,b = asn1_NOVALUE, c = true}} =
- asn1_wrapper:decode('DoubleEllipses','SetV2',Bytes5),
- ?line {ok,Bytes6} =
- asn1_wrapper:encode('DoubleEllipses','SetV2',
- #'SetV2'{a=10,b = false, c = true}),
- ?line {ok,#'Set'{a = 10, c = true}} =
- asn1_wrapper:decode('DoubleEllipses','Set',Bytes6),
-
- ?line {ok,Bytes7} =
- asn1_wrapper:encode('DoubleEllipses','SetAlt',
- #'SetAlt'{a = 10, d = 12,
- b = [1,0,1,0], e = true,
- c = false, f = 14, g = 16}),
- ?line {ok,#'SetAltV2'{a = 10, d = 12,
- b = <<2#1010:4>>, e = true,
- h = asn1_NOVALUE, i = asn1_NOVALUE,
- c = false, f = 14, g = 16}} =
- asn1_wrapper:decode('DoubleEllipses','SetAltV2',Bytes7),
- ?line {ok,Bytes8} =
- asn1_wrapper:encode('DoubleEllipses','SetAltV2',
- #'SetAltV2'{a = 10, d = 12,
- b = [1,0,1,0], e = true,
- h = "PS", i = 13,
- c = false, f = 14, g = 16}),
- ?line {ok,#'SetAlt'{a = 10, d = 12,
- b = <<2#1010:4>>, e = true,
- c = false, f = 14, g = 16}} =
- asn1_wrapper:decode('DoubleEllipses','SetAlt',Bytes8),
+ roundtrip('Set', #'Set'{a=10,c=true}),
+ roundtrip('SetV2', #'SetV2'{a=10,b=false,c=true}),
+ roundtrip('SetAlt',
+ #'SetAlt'{a=10,d=12,
+ b = <<2#1010:4>>,
+ e=true,c=false,f=14,g=16}),
+ roundtrip('SetAltV2',
+ #'SetAltV2'{a=10,d=12,
+ b = <<2#1010:4>>,
+ e=true,h="PS",i=13,c=false,f=14,g=16}),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('DoubleEllipses', T, V).
diff --git a/lib/asn1/test/testEnumExt.erl b/lib/asn1/test/testEnumExt.erl
index cbc13ee6da..c66adaf949 100644
--- a/lib/asn1/test/testEnumExt.erl
+++ b/lib/asn1/test/testEnumExt.erl
@@ -33,7 +33,7 @@ main(Rule) when Rule =:= per; Rule =:= uper ->
%% ENUMERATED with extensionmark (value is an extensionvalue)
Or = roundtrip('Ext1', orange),
%% unknown extensionvalue
- {ok,{asn1_enum,0}} = asn1_wrapper:decode('EnumExt','Ext',Or),
+ {ok,{asn1_enum,0}} = 'EnumExt':decode('Ext', Or),
%% ENUMERATED no extensionmark
B64 = <<64>>,
@@ -45,12 +45,12 @@ main(ber) ->
roundtrip('Ext', red),
%% value is an extensionvalue
- {ok,Bytes1_1} = asn1_wrapper:encode('EnumExt','Ext1',orange),
- {ok,{asn1_enum,7}} = asn1_wrapper:decode('EnumExt','Ext',lists:flatten(Bytes1_1)),
+ {ok,Bytes1_1} = 'EnumExt':encode('Ext1', orange),
+ {ok,{asn1_enum,7}} = 'EnumExt':decode('Ext', Bytes1_1),
%% ENUMERATED no extensionmark
roundtrip('Noext', red),
- ?line {error,{asn1,_}} = (catch asn1_wrapper:encode('EnumExt','Noext',orange)),
+ {error,{asn1,_}} = (catch 'EnumExt':encode('Noext', orange)),
%% ENUMERATED with atom 'com'
roundtrip('Globalstate', preop),
@@ -77,9 +77,7 @@ common(Erule) ->
ok.
roundtrip(Type, Value) ->
- {ok,Encoded} = 'EnumExt':encode(Type, Value),
- {ok,Value} = 'EnumExt':decode(Type, Encoded),
- Encoded.
+ asn1_test_lib:roundtrip_enc('EnumExt', Type, Value).
v_roundtrip(Erule, Type, Value) ->
Encoded = roundtrip(Type, Value),
diff --git a/lib/asn1/test/testFragmented.erl b/lib/asn1/test/testFragmented.erl
index c391ba8305..8d5fa07a5b 100644
--- a/lib/asn1/test/testFragmented.erl
+++ b/lib/asn1/test/testFragmented.erl
@@ -37,6 +37,4 @@ main(_Erule) ->
ok.
roundtrip(T, V) ->
- {ok,E} = 'Fragmented':encode(T, V),
- {ok,V} = 'Fragmented':decode(T, E),
- ok.
+ asn1_test_lib:roundtrip('Fragmented', T, V).
diff --git a/lib/asn1/test/testINSTANCE_OF.erl b/lib/asn1/test/testINSTANCE_OF.erl
index ce411beb92..c855ca3c06 100644
--- a/lib/asn1/test/testINSTANCE_OF.erl
+++ b/lib/asn1/test/testINSTANCE_OF.erl
@@ -18,46 +18,23 @@
%%
%%
-module(testINSTANCE_OF).
-
-export([main/1]).
-include_lib("test_server/include/test_server.hrl").
-main(Erule) ->
+main(_Erule) ->
+ Int = roundtrip('Int', 3),
- ?line {ok,Integer} = asn1_wrapper:encode('INSTANCEOF','Int',3),
- Int = list_to_binary(Integer),
ValotherName = {otherName,{'INSTANCE OF',{2,4},Int}},
+ _ = roundtrip('GeneralName', ValotherName),
+
VallastName1 = {lastName,{'GeneralName_lastName',{2,4},12}},
+ _ = roundtrip('GeneralName', VallastName1),
+
VallastName2 = {lastName,{'GeneralName_lastName',{2,3,4},
{'Seq',12,true}}},
- ?line {ok,BytesoN}=
- asn1_wrapper:encode('INSTANCEOF','GeneralName',ValotherName),
- ?line {ok,Res1={otherName,_}} =
- asn1_wrapper:decode('INSTANCEOF','GeneralName',BytesoN),
- ?line ok = test_encdec(Erule,Int,Res1),
-
- ?line {ok,ByteslN1}=
- asn1_wrapper:encode('INSTANCEOF','GeneralName',VallastName1),
- ?line {ok,Res2={lastName,_}} =
- asn1_wrapper:decode('INSTANCEOF','GeneralName',ByteslN1),
- ?line test_encdec(Erule,Res2),
-
- ?line {ok,ByteslN2}=
- asn1_wrapper:encode('INSTANCEOF','GeneralName',VallastName2),
- ?line {ok,Res3={lastName,_}} =
- asn1_wrapper:decode('INSTANCEOF','GeneralName',ByteslN2),
- ?line test_encdec(Erule,Res3).
-
-test_encdec(_Erule,Int,{otherName,{'INSTANCE OF',{2,4},Int}}) ->
- ok;
-test_encdec(Erule,Int,R={otherName,{'INSTANCE OF',{2,4},_Int2}}) ->
- {error,{Erule,Int,R}}.
+ _ = roundtrip('GeneralName', VallastName2),
+ ok.
-test_encdec(_Erule,{lastName,{'GeneralName_lastName',{2,4},12}}) ->
- ok;
-test_encdec(_Erule,{lastName,{'GeneralName_lastName',{2,3,4},
- {'Seq',12,true}}}) ->
- ok;
-test_encdec(Erule,Res) ->
- {error,{Erule,Res}}.
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip_enc('INSTANCEOF', T, V).
diff --git a/lib/asn1/test/testInfObj.erl b/lib/asn1/test/testInfObj.erl
index 76f216fdad..cd335e1023 100644
--- a/lib/asn1/test/testInfObj.erl
+++ b/lib/asn1/test/testInfObj.erl
@@ -121,9 +121,7 @@ main(_Erule) ->
{'Multiple-Optionals',1,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}).
roundtrip(M, T, V) ->
- {ok,Enc} = M:encode(T, V),
- {ok,V} = M:decode(T, Enc),
- ok.
+ asn1_test_lib:roundtrip(M, T, V).
enc_dec(M, T, V0) ->
{ok,Enc} = M:encode(T, V0),
diff --git a/lib/asn1/test/testInfObjectClass.erl b/lib/asn1/test/testInfObjectClass.erl
index 98408502c6..c36c05a2ea 100644
--- a/lib/asn1/test/testInfObjectClass.erl
+++ b/lib/asn1/test/testInfObjectClass.erl
@@ -29,24 +29,22 @@ main(Rule) ->
%% this test is added for OTP-4591, to test that elements in decoded
%% value has terms in right order.
Val = {'Seq',12,13,2},
- ?line {ok,Bytes}= asn1_wrapper:encode('InfClass','Seq',Val),
- ?line {ok,Val} = asn1_wrapper:decode('InfClass','Seq',Bytes),
+ roundtrip('Seq', Val),
%% OTP-5783
- ?line {error,{asn1,{'Type not compatible with table constraint',
- {component,'ArgumentType'},
- {value,_},_}}} = asn1_wrapper:encode('InfClass','Seq',
- {'Seq',12,13,1}),
+ {error,{asn1,{'Type not compatible with table constraint',
+ {component,'ArgumentType'},
+ {value,_},_}}} = 'InfClass':encode('Seq', {'Seq',12,13,1}),
Bytes2 = case Rule of
ber ->
<<48,9,2,1,12,2,1,11,2,1,1>>;
_ ->
- <<1,12,1,11,1,1>>
+ <<1,12,1,11,1,1>>
end,
- ?line {error,{asn1,{'Type not compatible with table constraint',
- {{component,_},
- {value,_B},_}}}} =
- asn1_wrapper:decode('InfClass','Seq',Bytes2).
+ {error,{asn1,{'Type not compatible with table constraint',
+ {{component,_},
+ {value,_B},_}}}} = 'InfClass':decode('Seq', Bytes2),
+ ok.
-
-
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('InfClass', T, V).
diff --git a/lib/asn1/test/testMegaco.erl b/lib/asn1/test/testMegaco.erl
index f4edcebb7e..644042b484 100644
--- a/lib/asn1/test/testMegaco.erl
+++ b/lib/asn1/test/testMegaco.erl
@@ -20,165 +20,28 @@
-module(testMegaco).
--export([compile/3,main/2,msg11/0]).
+-export([compile/3,main/2]).
-include_lib("test_server/include/test_server.hrl").
--define(MID, {ip4Address, #'IP4Address'{address = [124, 124, 124, 222],
- portNumber = 55555}}).
--define(A4444, ["11111111"]).
--record('MegacoMessage',
- {
- authHeader = asn1_NOVALUE,
- mess
- }).
-
--record('Message',
- {
- version,
- mId,
- messageBody
- }). % with extension mark
-
--record('IP4Address',
- {
- address,
- portNumber = asn1_NOVALUE
- }).
-
--record('TransactionRequest',
- {
- transactionId,
- actions = []
- }). % with extension mark
-
--record('ActionRequest',
- {
- contextId,
- contextRequest = asn1_NOVALUE,
- contextAttrAuditReq = asn1_NOVALUE,
- commandRequests = []
- }).
-
--record('CommandRequest',
- {
- command,
- optional = asn1_NOVALUE,
- wildcardReturn = asn1_NOVALUE
- }). % with extension mark
-
--record('NotifyRequest',
- {
- terminationID,
- observedEventsDescriptor,
- errorDescriptor = asn1_NOVALUE
- }). % with extension mark
-
--record('ObservedEventsDescriptor',
- {
- requestId,
- observedEventLst = []
- }).
-
--record('ObservedEvent',
- {
- eventName,
- streamID = asn1_NOVALUE,
- eventParList = [],
- timeNotation = asn1_NOVALUE
- }). % with extension mark
-
--record('EventParameter',
- {
- eventParameterName,
- value
- }).
-
--record('TimeNotation',
- {
- date,
- time
- }).
-
--record(megaco_term_id, {contains_wildcards = ["f"], id}).
-
-
-compile(_Config,ber,[optimize]) ->
- {ok,no_module,no_module};
-compile(_Config,per,[optimize]) ->
- {ok,no_module,no_module};
-compile(Config,Erule,Options) ->
+compile(Config, Erule, Options) ->
asn1_test_lib:compile("MEDIA-GATEWAY-CONTROL.asn", Config, [Erule|Options]),
asn1_test_lib:compile("OLD-MEDIA-GATEWAY-CONTROL.asn", Config, [Erule|Options]),
{ok,'OLD-MEDIA-GATEWAY-CONTROL','MEDIA-GATEWAY-CONTROL'}.
-
main(no_module,_) -> ok;
main('OLD-MEDIA-GATEWAY-CONTROL',Config) ->
-% Msg = msg11(),
CaseDir = ?config(case_dir, Config),
{ok,Msg} = asn1ct:value('OLD-MEDIA-GATEWAY-CONTROL','MegacoMessage',
[{i, CaseDir}]),
- ?line {ok,Bytes} = asn1_wrapper:encode('OLD-MEDIA-GATEWAY-CONTROL',
- 'MegacoMessage',Msg),
- ?line {ok,Msg} = asn1_wrapper:decode('OLD-MEDIA-GATEWAY-CONTROL',
- 'MegacoMessage',
- Bytes),
+ asn1_test_lib:roundtrip('OLD-MEDIA-GATEWAY-CONTROL', 'MegacoMessage', Msg),
ok;
-main(Mod='MEDIA-GATEWAY-CONTROL',Config) ->
- ?line DataDir = ?config(data_dir,Config),
- io:format("DataDir:~p~n",[DataDir]),
- ?line {ok,FilenameList} = file:list_dir(filename:join([DataDir,
- megacomessages])),
- %% remove any junk files that may be in the megacomessage directory
- Pred = fun(X) ->
- case lists:reverse(X) of
- [$l,$a,$v,$.|_R] ->true;
- _ -> false
- end
- end,
- MegacoMsgFilenameList = lists:filter(Pred,FilenameList),
-
- Fun = fun(F) ->
- M = read_msg(filename:join([DataDir,megacomessages,F])),
- {ok,B} = asn1_wrapper:encode(Mod,element(1,M),M),
- {ok,M} = asn1_wrapper:decode(Mod,element(1,M),B)
- end,
- ?line lists:foreach(Fun,MegacoMsgFilenameList),
- ok.
-
-read_msg(File) ->
- case file:read_file(File) of
- {ok,Bin} ->
- binary_to_term(Bin);
- _ ->
- io:format("couldn't read file ~p~n",[File])
- end.
-
-
-request(Mid, TransId, ContextId, CmdReq) when is_list(CmdReq) ->
- Actions = [#'ActionRequest'{contextId = ContextId,
- commandRequests = CmdReq}],
- Req = {transactions,
- [{transactionRequest,
- #'TransactionRequest'{transactionId = TransId,
- actions = Actions}}]},
- #'MegacoMessage'{mess = #'Message'{version = 1,
- mId = Mid,
- messageBody = Req}}.
-
-msg11() ->
- TimeStamp = #'TimeNotation'{date = "19990729",
- time = "22012001"},
- Parm = #'EventParameter'{eventParameterName = "ds",
- value = "916135551212"},
-
- Event = #'ObservedEvent'{eventName = "ddce",
- timeNotation = TimeStamp,
- eventParList = [Parm]},
- Desc = #'ObservedEventsDescriptor'{requestId = 2223,
- observedEventLst = [Event]},
- NotifyReq = #'NotifyRequest'{terminationID = [#megaco_term_id{id = ?A4444}],
- observedEventsDescriptor = Desc},
- CmdReq = #'CommandRequest'{command = {notifyReq, NotifyReq}},
- request(?MID, 10002, 0, [CmdReq]).
+main('MEDIA-GATEWAY-CONTROL'=Mod, Config) ->
+ DataDir = ?config(data_dir, Config),
+ Files = filelib:wildcard(filename:join([DataDir,megacomessages,"*.val"])),
+ lists:foreach(fun(File) ->
+ {ok,Bin} = file:read_file(File),
+ V = binary_to_term(Bin),
+ T = element(1, V),
+ asn1_test_lib:roundtrip(Mod, T, V)
+ end, Files).
diff --git a/lib/asn1/test/testMergeCompile.erl b/lib/asn1/test/testMergeCompile.erl
index 8ef7ba3458..7cda71c441 100644
--- a/lib/asn1/test/testMergeCompile.erl
+++ b/lib/asn1/test/testMergeCompile.erl
@@ -30,42 +30,35 @@
main(Erule) ->
%% test of module MS.set.asn that tests OTP-4492: different tagdefault in
%% modules and types with same name in modules
- ?line MSVal = {'Type4M2',8,true,three,"OCTET STRING"},
- ?line {ok,MSBytes} = asn1_wrapper:encode('MS','Type4M2',MSVal),
- ?line {ok,MSVal} = asn1_wrapper:decode('MS','Type4M2',MSBytes),
-
+ MSVal = {'Type4M2',8,true,three,"OCTET STRING"},
+ asn1_test_lib:roundtrip('MS', 'Type4M2', MSVal),
%% test of RANAP.set.asn1
- ?line _PIEVal = [{'ProtocolIE-Field',4,ignore,{'Cause',{radioNetwork,{'CauseRadioNetwork','rab-pre-empted'}}}}],
PIEVal2 = [{'ProtocolIE-Field',4,ignore,{radioNetwork,'rab-pre-empted'}}],
- ?line _PEVal = [{'ProtocolExtensionField',[0]}],
-%% ?line EncVal = asn1rt_per_v1:encode_integer([],100),
- ?line EncVal =
+ EncVal =
case Erule of
per ->
<<1,100>>;
uper ->
<<1,100>>;
ber ->
- [2,1,1]
+ <<2,1,1>>
end,
- ?line PEVal2 = [{dummy,1,ignore,EncVal},{dummy,2,reject,EncVal}],
- ?line Val2 =
+ PEVal2 = [{'ProtocolExtensionField',1,ignore,EncVal},
+ {'ProtocolExtensionField',2,reject,EncVal}],
+ Val2 =
#'InitiatingMessage'{procedureCode=1,
criticality=ignore,
value=#'Iu-ReleaseCommand'{protocolIEs=PIEVal2,
protocolExtensions=asn1_NOVALUE}},
- ?line {ok,Bytes2} = asn1_wrapper:encode('RANAPSET','InitiatingMessage',Val2),
- ?line {ok,_Ret2} = asn1_wrapper:decode('RANAPSET','InitiatingMessage',Bytes2),
-
- ?line Val3 =
+ asn1_test_lib:roundtrip('RANAPSET', 'InitiatingMessage', Val2),
+ Val3 =
#'InitiatingMessage'{procedureCode=1,
criticality=ignore,
value=#'Iu-ReleaseCommand'{protocolIEs=PIEVal2,
protocolExtensions=PEVal2}},
- ?line {ok,Bytes3} = asn1_wrapper:encode('RANAPSET','InitiatingMessage',Val3),
- ?line {ok,_Ret3} = asn1_wrapper:decode('RANAPSET','InitiatingMessage',Bytes3).
+ asn1_test_lib:roundtrip('RANAPSET', 'InitiatingMessage', Val3).
mvrasn(Erule) ->
@@ -83,78 +76,73 @@ mvrasn(Erule) ->
?line ok = test(mvrasn6,'InsertSubscriberDataArg').
test(isd)->
- EncPdu = [48,128,129,7,145,148,113,50,1,0,241,131,1,0,176,128,5,0,161,128,48,22,2,1,1,144,2,241,33,145,4,0,1,2,3,146,3,36,131,16,148,2,1,42,48,35,2,1,2,144,2,241,33,145,4,255,255,255,255,146,3,37,147,18,147,0,148,13,7,67,79,77,80,65,78,89,4,67,79,77,53,48,28,2,1,3,144,2,241,33,146,3,26,98,31,148,14,9,67,79,77,80,65,78,89,49,50,3,67,79,77,0,0,0,0,152,1,2,0,0],
-
- ?line {ok,_} = asn1_wrapper:decode('Mvrasn4',
- 'InsertSubscriberDataArg',
- EncPdu),
+ EncPdu = <<48,128,129,7,145,148,113,50,1,0,241,131,1,0,176,128,5,0,
+ 161,128,48,22,2,1,1,144,2,241,33,145,4,0,1,2,3,146,3,36,
+ 131,16,148,2,1,42,48,35,2,1,2,144,2,241,33,145,4,255,255,
+ 255,255,146,3,37,147,18,147,0,148,13,7,67,79,77,80,65,78,
+ 89,4,67,79,77,53,48,28,2,1,3,144,2,241,33,146,3,26,98,31,
+ 148,14,9,67,79,77,80,65,78,89,49,50,3,67,79,77,0,0,0,0,
+ 152,1,2,0,0>>,
+ {ok,_} = 'Mvrasn4':decode('InsertSubscriberDataArg', EncPdu),
ok;
%
% Problems with indefinite length encoding !!!
%
test(isd2)->
- EncPdu = [48, 128, 128, 8, 98, 2, 50, 1, 0, 0, 0, 241, 176, 128, 161, 128, 48, 128, 2, 1, 1, 144, 2, 241, 33, 145, 4, 255, 23, 12, 1, 146, 3, 9, 17, 1, 147, 0, 148, 13, 7, 67, 79, 77, 80, 65, 78, 89, 4, 67, 79, 77, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-
- ?line {ok,_DecPdu} = asn1_wrapper:decode('Mvrasn4',
- 'InsertSubscriberDataArg',
- EncPdu),
-
+ EncPdu = <<48,128,128,8,98,2,50,1,0,0,0,241,176,128,161,128,48,128,2,1,1,144,
+ 2,241,33,145,4,255,23,12,1,146,3,9,17,1,147,0,148,13,7,67,79,77,80,
+ 65,78,89,4,67,79,77,53,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>,
+ {ok,_DecPdu} = 'Mvrasn4':decode('InsertSubscriberDataArg', EncPdu),
ok;
%
% Is doing fine, although there is indefinite encoding used... !!!
%
test(dsd)->
- EncPdu = [48, 128, 128, 8, 98, 2, 50, 1, 0, 0, 0, 241, 170, 2, 5, 0, 0, 0, 0, 0],
-
- ?line {ok,_DecPdu} = asn1_wrapper:decode('Mvrasn4',
- 'DeleteSubscriberDataArg',
- EncPdu),
-
+ EncPdu = <<48,128,128,8,98,2,50,1,0,0,0,241,170,2,5,0,0,0,0,0>>,
+ {ok,_DecPdu} = 'Mvrasn4':decode('DeleteSubscriberDataArg', EncPdu),
ok;
%
% Is doing fine !!!
%
test(ul_res)->
- EncPdu = [48, 9, 4, 7, 145, 148, 113, 66, 16, 17, 241],
-
- ?line {ok,_DecPdu} = asn1_wrapper:decode('Mvrasn4',
- 'UpdateGprsLocationRes',
- EncPdu),
-
+ EncPdu = <<48,9,4,7,145,148,113,66,16,17,241>>,
+ {ok,_DecPdu} = 'Mvrasn4':decode('UpdateGprsLocationRes', EncPdu),
ok;
test(seqofseq) ->
- {ok,_V} = asn1_wrapper:decode('Mvrasn4',
- 'SentParameters',
- [48,129,190,161,128,4,16,176,197,182,68,41,243,188,205,123,13,9,145,206,200,144,102,4,4,176,197,182,68,4,8,41,243,188,205,123,13,9,145,0,0,161,128,4,16,39,0,3,117,35,189,130,21,42,104,49,194,212,24,151,234,4,4,39,0,3,117,4,8,35,189,130,21,42,104,49,194,0,0,161,128,4,16,62,207,166,59,71,29,37,97,120,25,132,80,144,251,161,123,4,4,62,207,166,59,4,8,71,29,37,97,120,25,132,80,0,0,161,128,4,16,95,183,173,151,17,76,148,146,248,102,127,215,102,224,39,60,4,4,95,183,173,151,4,8,17,76,148,146,248,102,127,215,0,0,161,128,4,16,41,198,247,157,117,190,203,170,91,146,88,91,223,220,188,16,4,4,41,198,247,157,4,8,117,190,203,170,91,146,88,91,0,0]),
+ EncPdu = <<48,129,190,161,128,4,16,176,197,182,68,41,243,188,205,123,13,
+ 9,145,206,200,144,102,4,4,176,197,182,68,4,8,41,243,188,205,
+ 123,13,9,145,0,0,161,128,4,16,39,0,3,117,35,189,130,21,42,104,
+ 49,194,212,24,151,234,4,4,39,0,3,117,4,8,35,189,130,21,42,104,
+ 49,194,0,0,161,128,4,16,62,207,166,59,71,29,37,97,120,25,132,
+ 80,144,251,161,123,4,4,62,207,166,59,4,8,71,29,37,97,120,25,
+ 132,80,0,0,161,128,4,16,95,183,173,151,17,76,148,146,248,102,
+ 127,215,102,224,39,60,4,4,95,183,173,151,4,8,17,76,148,146,248,
+ 102,127,215,0,0,161,128,4,16,41,198,247,157,117,190,203,170,91,
+ 146,88,91,223,220,188,16,4,4,41,198,247,157,4,8,117,190,203,170,91,146,88,91,0,0>>,
+ {ok,_V} = 'Mvrasn4':decode('SentParameters', EncPdu),
ok;
test('InsertSubscriberDataArg') ->
- {ok,_V} =
- asn1_wrapper:decode('Mvrasn4','InsertSubscriberDataArg',
- [16#30,16#80,16#81,16#07,16#91,16#94,
- 16#71,16#92,16#00,16#35,16#80,16#83,
- 16#01,16#00,16#A6,16#06,16#04,16#01,
- 16#21,16#04,16#01,16#22,16#B0,16#80,
- 16#05,16#00,16#A1,16#80,16#30,16#1A,
- 16#02,16#01,16#01,16#90,16#02,16#F1,
- 16#21,16#92,16#03,16#0D,16#92,16#1F,
- 16#94,16#0C,16#03,16#53,16#49,16#4D,
- 16#03,16#47,16#53,16#4E,16#03,16#4C,
- 16#4B,16#50,16#00,16#00,16#00,16#00,
- 16#98,16#01,16#00,16#00,16#00]),
+ EncPdu = <<16#30,16#80,16#81,16#07,16#91,16#94,
+ 16#71,16#92,16#00,16#35,16#80,16#83,
+ 16#01,16#00,16#A6,16#06,16#04,16#01,
+ 16#21,16#04,16#01,16#22,16#B0,16#80,
+ 16#05,16#00,16#A1,16#80,16#30,16#1A,
+ 16#02,16#01,16#01,16#90,16#02,16#F1,
+ 16#21,16#92,16#03,16#0D,16#92,16#1F,
+ 16#94,16#0C,16#03,16#53,16#49,16#4D,
+ 16#03,16#47,16#53,16#4E,16#03,16#4C,
+ 16#4B,16#50,16#00,16#00,16#00,16#00,
+ 16#98,16#01,16#00,16#00,16#00>>,
+ {ok,_V} = 'Mvrasn4':decode('InsertSubscriberDataArg', EncPdu),
ok.
test(mvrasn6,'InsertSubscriberDataArg') ->
Val = {'InsertSubscriberDataArg',"IMSI","Address","C",serviceGranted,["abc","cde"],["tele","serv","ice"],asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,{'NAEA-PreferredCI',"NCC",asn1_NOVALUE},{'GPRSSubscriptionData','NULL',[{'PDP-Context',49,"PT","PDP-Address","QoS",'NULL',"APN",asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}],asn1_NOVALUE},'NULL',onlyMSC,{'LSAInformation','NULL',accessOutsideLSAsAllowed,[{'LSAData',"LSA","L",'NULL',asn1_NOVALUE},{'LSAData',"LSA","L",'NULL',asn1_NOVALUE}],asn1_NOVALUE},'NULL',{'LCSInformation',["Addr","ess","string"],[{'LCS-PrivacyClass',"S","ExtSS",notifyLocationAllowed,[{'ExternalClient',{'LCSClientExternalID',"Addr",asn1_NOVALUE},asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}],[broadcastService,anonymousLocation,targetMSsubscribedService],asn1_NOVALUE}],asn1_NOVALUE},100,"age",{'MC-SS-Info',"S","ExtSS",5,4,asn1_NOVALUE},"C",{'SGSN-CAMEL-SubscriptionInfo',{'GPRS-CSI',[{'GPRS-CamelTDPData',attach,13,"Addr",continueTransaction,asn1_NOVALUE}],11,asn1_NOVALUE,'NULL','NULL'},{'SMS-CSI',[{'SMS-CAMEL-TDP-DataList','sms-CollectedInfo',13,"Addr",continueTransaction,asn1_NOVALUE}],11,asn1_NOVALUE,'NULL','NULL'},asn1_NOVALUE},"ON"},
-
- {ok,Bytes}=
- asn1_wrapper:encode('Mvrasn6','InsertSubscriberDataArg',Val),
-
- {ok,_Res} =
- asn1_wrapper:decode('Mvrasn6','InsertSubscriberDataArg',Bytes),
-
+ {ok,Bytes} = 'Mvrasn6':encode('InsertSubscriberDataArg', Val),
+ {ok,_} = 'Mvrasn6':decode('InsertSubscriberDataArg', Bytes),
ok.
diff --git a/lib/asn1/test/testNBAPsystem.erl b/lib/asn1/test/testNBAPsystem.erl
index 0f4459f5b2..57cb483374 100644
--- a/lib/asn1/test/testNBAPsystem.erl
+++ b/lib/asn1/test/testNBAPsystem.erl
@@ -19,7 +19,7 @@
%%
-module(testNBAPsystem).
--export([compile/2,test/2,cell_setup_req_msg/0]).
+-export([compile/2,test/2]).
-include_lib("test_server/include/test_server.hrl").
@@ -96,23 +96,16 @@ test(_Erule,Config) ->
ticket_5812(Config) ->
?line Msg = v_5812(),
- ?line {ok,B2} = asn1_wrapper:encode('NBAP-PDU-Discriptions',
- 'NBAP-PDU',
- Msg),
+ {ok,B2} = 'NBAP-PDU-Discriptions':encode('NBAP-PDU', Msg),
V = <<0,28,74,0,3,48,0,0,1,0,123,64,41,0,0,0,126,64,35,95,208,2,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,145,0,1,205,0,0,0,0,2,98,64,1,128>>,
?line ok = compare(V,B2),
- ?line {ok,Msg2} = asn1_wrapper:decode('NBAP-PDU-Discriptions',
- 'NBAP-PDU',B2),
+ {ok,Msg2} = 'NBAP-PDU-Discriptions':decode('NBAP-PDU', B2),
?line ok = check_record_names(Msg2,Config).
enc_audit_req_msg() ->
Msg = {initiatingMessage, audit_req_msg()},
- ?line {ok,B}=asn1_wrapper:encode('NBAP-PDU-Discriptions',
- 'NBAP-PDU',
- Msg),
- ?line {ok,_Msg}=asn1_wrapper:decode('NBAP-PDU-Discriptions',
- 'NBAP-PDU',
- B),
+ {ok,B} = 'NBAP-PDU-Discriptions':encode('NBAP-PDU', Msg),
+ {ok,_Msg} = 'NBAP-PDU-Discriptions':decode('NBAP-PDU', B),
?line {initiatingMessage,
#'InitiatingMessage'{value=#'AuditRequest'{protocolIEs=[{_,114,ignore,_}],
protocolExtensions = asn1_NOVALUE}}} = _Msg,
@@ -121,12 +114,8 @@ enc_audit_req_msg() ->
cell_setup_req_msg_test() ->
Msg = {initiatingMessage, cell_setup_req_msg()},
- ?line {ok,B}=asn1_wrapper:encode('NBAP-PDU-Discriptions',
- 'NBAP-PDU',
- Msg),
- ?line {ok,_Msg}=asn1_wrapper:decode('NBAP-PDU-Discriptions',
- 'NBAP-PDU',
- B),
+ {ok,B} = 'NBAP-PDU-Discriptions':encode('NBAP-PDU', Msg),
+ {ok,_Msg} = 'NBAP-PDU-Discriptions':decode('NBAP-PDU', B),
io:format("Msg: ~P~n~n_Msg: ~P~n",[Msg,15,_Msg,15]),
ok.
diff --git a/lib/asn1/test/testOpenTypeImplicitTag.erl b/lib/asn1/test/testOpenTypeImplicitTag.erl
index a37d8004ef..0fbf70d037 100644
--- a/lib/asn1/test/testOpenTypeImplicitTag.erl
+++ b/lib/asn1/test/testOpenTypeImplicitTag.erl
@@ -24,18 +24,9 @@
-include_lib("test_server/include/test_server.hrl").
main(_Rules) ->
-
- ?line {ok,Bytes1} =
- asn1_wrapper:encode('OpenTypeImplicitTag','Seq',
- {'Seq',[1,1,255],[1,1,255],12,[1,1,255]}),
- ?line {ok,{'Seq',_,_,12,_}} =
- asn1_wrapper:decode('OpenTypeImplicitTag','Seq',
- lists:flatten(Bytes1)),
-
- ?line {ok,Bytes2} =
- asn1_wrapper:encode('OpenTypeImplicitTag','Seq',
- {'Seq',[1,1,255],asn1_NOVALUE,12,[1,1,255]}),
- ?line {ok,{'Seq',_,asn1_NOVALUE,12,_}} =
- asn1_wrapper:decode('OpenTypeImplicitTag','Seq',
- lists:flatten(Bytes2)),
+ roundtrip('Seq', {'Seq',<<1,1,255>>,<<1,1,255>>,12,<<1,1,255>>}),
+ roundtrip('Seq', {'Seq',<<1,1,255>>,asn1_NOVALUE,12,<<1,1,255>>}),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('OpenTypeImplicitTag', T, V).
diff --git a/lib/asn1/test/testOpt.erl b/lib/asn1/test/testOpt.erl
index a1ad8099b5..a6dcccad15 100644
--- a/lib/asn1/test/testOpt.erl
+++ b/lib/asn1/test/testOpt.erl
@@ -18,8 +18,6 @@
%%
%%
-module(testOpt).
-
--export([compile/2]).
-export([main/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -39,92 +37,29 @@
bool32 = asn1_NOVALUE,
bool33 = asn1_NOVALUE}).
-
-compile(Config,Rules) ->
-
- ?line DataDir = ?config(data_dir,Config),
- ?line OutDir = ?config(priv_dir,Config),
- ?line true = code:add_patha(?config(priv_dir,Config)),
- ?line ok = asn1ct:compile(DataDir ++ "Opt",[Rules,{outdir,OutDir}]).
-
-
-
main(_Rules) ->
-
- ?line {ok,Bytes11} = asn1_wrapper:encode('Opt','Opt1',#'Opt1'{bool0 = true,
- bool1 = true,
- bool2 = true,
- bool3 = true}),
- ?line {ok,{'Opt1',true,true,true,true}} =
- asn1_wrapper:decode('Opt','Opt1',lists:flatten(Bytes11)),
+ roundtrip('Opt1', #'Opt1'{bool0=true,bool1=true,bool2=true,bool3=true}),
+ roundtrip('Opt1', #'Opt1'{bool0=true,bool1=asn1_NOVALUE,bool2=asn1_NOVALUE,
+ bool3=asn1_NOVALUE}),
+ roundtrip('Opt1', #'Opt1'{bool0=true,bool1=asn1_NOVALUE,bool2=false,bool3=asn1_NOVALUE}),
+ roundtrip('Opt1', #'Opt1'{bool0=false,bool1=asn1_NOVALUE,bool2=asn1_NOVALUE,bool3=false}),
- ?line {ok,Bytes12} = asn1_wrapper:encode('Opt','Opt1',#'Opt1'{bool0 = true}),
- ?line {ok,{'Opt1',true,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}} =
- asn1_wrapper:decode('Opt','Opt1',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} = asn1_wrapper:encode('Opt','Opt1',#'Opt1'{bool0 = true,
- bool2 = false}),
- ?line {ok,{'Opt1',true,asn1_NOVALUE,false,asn1_NOVALUE}} =
- asn1_wrapper:decode('Opt','Opt1',lists:flatten(Bytes13)),
-
- ?line {ok,Bytes14} = asn1_wrapper:encode('Opt','Opt1',#'Opt1'{bool0 = false,
- bool3 = false}),
- ?line {ok,{'Opt1',false,asn1_NOVALUE,asn1_NOVALUE,false}} =
- asn1_wrapper:decode('Opt','Opt1',lists:flatten(Bytes14)),
-
-
-
-
- ?line {ok,Bytes21} = asn1_wrapper:encode('Opt','Opt2',#'Opt2'{bool10 = false,
- bool11 = false,
- bool12 = false,
- bool13 = false}),
- ?line {ok,{'Opt2',false,false,false,false}} =
- asn1_wrapper:decode('Opt','Opt2',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('Opt','Opt2',#'Opt2'{bool10 = true,
- bool13 = false}),
- ?line {ok,{'Opt2',true,asn1_NOVALUE,asn1_NOVALUE,false}} =
- asn1_wrapper:decode('Opt','Opt2',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes23} = asn1_wrapper:encode('Opt','Opt2',#'Opt2'{bool10 = true,
- bool11 = false,
- bool13 = false}),
- ?line {ok,{'Opt2',true,false,asn1_NOVALUE,false}} =
- asn1_wrapper:decode('Opt','Opt2',lists:flatten(Bytes23)),
-
- ?line {ok,Bytes24} = asn1_wrapper:encode('Opt','Opt2',#'Opt2'{bool10 = false,
- bool12 = false,
- bool13 = false}),
- ?line {ok,{'Opt2',false,asn1_NOVALUE,false,false}} =
- asn1_wrapper:decode('Opt','Opt2',lists:flatten(Bytes24)),
-
-
-
-
- ?line {ok,Bytes31} = asn1_wrapper:encode('Opt','Opt3',#'Opt3'{bool30 = false,
- bool31 = false,
- bool32 = false,
- bool33 = false}),
- ?line {ok,{'Opt3',false,false,false,false}} =
- asn1_wrapper:decode('Opt','Opt3',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} = asn1_wrapper:encode('Opt','Opt3',#'Opt3'{}),
- ?line {ok,{'Opt3',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}} =
- asn1_wrapper:decode('Opt','Opt3',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes33} = asn1_wrapper:encode('Opt','Opt3',#'Opt3'{bool30 = true}),
- ?line {ok,{'Opt3',true,asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE}} =
- asn1_wrapper:decode('Opt','Opt3',lists:flatten(Bytes33)),
-
- ?line {ok,Bytes34} = asn1_wrapper:encode('Opt','Opt3',#'Opt3'{bool32 = false}),
- ?line {ok,{'Opt3',asn1_NOVALUE,asn1_NOVALUE,false,asn1_NOVALUE}} =
- asn1_wrapper:decode('Opt','Opt3',lists:flatten(Bytes34)),
-
- ?line {ok,Bytes35} = asn1_wrapper:encode('Opt','Opt3',#'Opt3'{bool33 = false}),
- ?line {ok,{'Opt3',asn1_NOVALUE,asn1_NOVALUE,asn1_NOVALUE,false}} =
- asn1_wrapper:decode('Opt','Opt3',lists:flatten(Bytes35)),
-
-
-
+ roundtrip('Opt2', #'Opt2'{bool10=false,bool11=false,bool12=false,bool13=false}),
+ roundtrip('Opt2', #'Opt2'{bool10=true,bool11=asn1_NOVALUE,bool12=asn1_NOVALUE,
+ bool13=false}),
+ roundtrip('Opt2', #'Opt2'{bool10=true,bool11=false,bool12=asn1_NOVALUE,bool13=false}),
+ roundtrip('Opt2', #'Opt2'{bool10=false,bool11=asn1_NOVALUE,bool12=false,bool13=false}),
+
+ roundtrip('Opt3', #'Opt3'{bool30=false,bool31=false,bool32=false,bool33=false}),
+ roundtrip('Opt3', #'Opt3'{bool30=asn1_NOVALUE,bool31=asn1_NOVALUE,bool32=asn1_NOVALUE,
+ bool33=asn1_NOVALUE}),
+ roundtrip('Opt3', #'Opt3'{bool30=true,bool31=asn1_NOVALUE,bool32=asn1_NOVALUE,
+ bool33=asn1_NOVALUE}),
+ roundtrip('Opt3', #'Opt3'{bool30=asn1_NOVALUE,bool31=asn1_NOVALUE,bool32=false,
+ bool33=asn1_NOVALUE}),
+ roundtrip('Opt3', #'Opt3'{bool30=asn1_NOVALUE,bool31=asn1_NOVALUE,bool32=asn1_NOVALUE,
+ bool33=false}),
ok.
+
+roundtrip(Type, Value) ->
+ asn1_test_lib:roundtrip('Opt', Type, Value).
diff --git a/lib/asn1/test/testParamBasic.erl b/lib/asn1/test/testParamBasic.erl
index a10468d592..3db89ca174 100644
--- a/lib/asn1/test/testParamBasic.erl
+++ b/lib/asn1/test/testParamBasic.erl
@@ -29,53 +29,27 @@
-record('T22',{number, string}).
main(Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('ParamBasic','T11',
- #'T11'{number = 11,
- string = "hello"}),
- ?line {ok,{'T11',11,"hello"}} =
- asn1_wrapper:decode('ParamBasic','T11',Bytes11),
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('ParamBasic','T12',
- #'T12'{number = 11,
- string = <<2#10101:5>>}),
- {ok,{'T12',11,<<2#10101:5>>}} =
- asn1_wrapper:decode('ParamBasic','T12',Bytes12),
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('ParamBasic','T21',
- #'T21'{number = 11,
- string = "hello"}),
- ?line {ok,{'T21',11,"hello"}} =
- asn1_wrapper:decode('ParamBasic','T21',Bytes13),
-
- ?line {ok,Bytes14} =
- asn1_wrapper:encode('ParamBasic','T22',
- #'T22'{number = 11,
- string = <<2#10101:5>>}),
- {ok,{'T22',11,<<2#10101:5>>}} =
- asn1_wrapper:decode('ParamBasic','T22',Bytes14),
-
+ roundtrip('T11', #'T11'{number=11,string="hello"}),
+ roundtrip('T12', #'T12'{number=11,string = <<21:5>>}),
+ roundtrip('T21', #'T21'{number=11,string="hello"}),
+ roundtrip('T22', #'T22'{number=11,string = <<21:5>>}),
case Rules of
der ->
-
- ?line {ok,[48,3,128,1,11]} =
- asn1_wrapper:encode('ParamBasic','T11',
- #'T11'{number = 11,
- string = "hej"}),
- ?line {ok,{'T11',11,"hej"}} =
- asn1_wrapper:decode('ParamBasic','T11',[48,3,128,1,11]),
-
- ?line {ok,[48,3,128,1,11]} =
- asn1_wrapper:encode('ParamBasic','T12',
- #'T12'{number = 11,
- string = [1,0,1,0]}),
-
- ?line {ok,{'T12',11,[1,0,1,0]}} =
- asn1_wrapper:decode('ParamBasic','T12',[48,3,128,1,11]);
+ <<48,3,128,1,11>> =
+ roundtrip_enc('T11', #'T11'{number=11,string="hej"}),
+ <<48,3,128,1,11>> =
+ roundtrip_enc('T12',
+ #'T12'{number=11,string=[1,0,1,0]},
+ #'T12'{number=11,string = <<10:4>>});
_ -> ok
end,
-
ok.
+
+roundtrip(Type, Value) ->
+ asn1_test_lib:roundtrip('ParamBasic', Type, Value).
+
+roundtrip_enc(Type, Value) ->
+ asn1_test_lib:roundtrip_enc('ParamBasic', Type, Value).
+
+roundtrip_enc(Type, Value, Expected) ->
+ asn1_test_lib:roundtrip_enc('ParamBasic', Type, Value, Expected).
diff --git a/lib/asn1/test/testParameterizedInfObj.erl b/lib/asn1/test/testParameterizedInfObj.erl
index 02847e502b..f3b4f9b170 100644
--- a/lib/asn1/test/testParameterizedInfObj.erl
+++ b/lib/asn1/test/testParameterizedInfObj.erl
@@ -41,49 +41,39 @@ param(Erule) ->
iE_Extensions =
[#'ProtocolExtensionField'{id=14,
criticality=reject,
- extensionValue=open_type(Erule,[0])},
+ extensionValue= <<0>>},
#'ProtocolExtensionField'{id=2,
criticality=ignore,
- extensionValue=open_type(Erule,[1])}]},
+ extensionValue= <<1>>}]},
BERVal = #'AllocationOrRetentionPriority'
{priorityLevel = true,
iE_Extensions =
[#'ProtocolExtensionField'{id=14,
criticality=reject,
- extensionValue=[2,1,0]},
+ extensionValue= <<2,1,0>>},
#'ProtocolExtensionField'{id=2,
criticality=ignore,
- extensionValue=[2,1,1]}]},
- ?line {ok,Bytes1} =
- case asn1_wrapper:erule(Erule) of
- per ->
- asn1_wrapper:encode('Param','AllocationOrRetentionPriority',
- PERVal);
- _ ->
- asn1_wrapper:encode('Param','AllocationOrRetentionPriority',
- BERVal)
- end,
-
- ?line {ok,{'AllocationOrRetentionPriority',true,[_R1,_R2]}} =
- asn1_wrapper:decode('Param','AllocationOrRetentionPriority',Bytes1),
+ extensionValue= <<2,1,1>>}]},
+ case Erule of
+ ber ->
+ roundtrip('AllocationOrRetentionPriority', BERVal);
+ per ->
+ roundtrip('AllocationOrRetentionPriority', PERVal);
+ uper ->
+ roundtrip('AllocationOrRetentionPriority', PERVal)
+ end,
%% test code for OTP-4242, ValueFromObject
- case asn1_wrapper:erule(Erule) of
+ case Erule of
ber ->
- ?line {ok,_Val3} = asn1_wrapper:decode('Param','OS1',[4,2,1,2]),
- ?line {error,_Reason1} =
- asn1_wrapper:decode('Param','OS1',[4,4,1,2,3,4]),
- ?line {error,_Reason2} =
- asn1_wrapper:decode('Param','OS2',[4,4,1,2,3,4]),
- ?line {ok,_Val4} = asn1_wrapper:decode('Param','OS1',[4,2,1,2]);
- per ->
- ?line {ok,Bytes3} =
- asn1_wrapper:encode('Param','OS1',[1,2]),
- ?line {ok,[1,2]} =
- asn1_wrapper:decode('Param','OS1',Bytes3),
- ?line {error,_Reason3} =
- asn1_wrapper:encode('Param','OS1',[1,2,3,4])
+ {ok,_Val3} = 'Param':decode('OS1', [4,2,1,2]),
+ {error,_Reason1} = 'Param':decode('OS1',[4,4,1,2,3,4]),
+ {error,_Reason2} = 'Param':decode('OS2',[4,4,1,2,3,4]),
+ {ok,_Val4} = 'Param':decode('OS1',[4,2,1,2]);
+ _ -> %per/uper
+ roundtrip('OS1', [1,2]),
+ {error,_Reason3} = 'Param':encode('OS1', [1,2,3,4])
end,
roundtrip('Scl', {'Scl',42,{a,9738654}}),
@@ -93,9 +83,7 @@ param(Erule) ->
ok.
roundtrip(T, V) ->
- {ok,Enc} = 'Param':encode(T, V),
- {ok,V} = 'Param':decode(T, Enc),
- ok.
+ asn1_test_lib:roundtrip('Param', T, V).
ranap(_Erule) ->
@@ -106,16 +94,11 @@ ranap(_Erule) ->
value=#'Iu-ReleaseCommand'{protocolIEs=PIEVal2,
protocolExtensions=asn1_NOVALUE}},
- ?line {ok,Bytes2} = asn1_wrapper:encode('RANAP','InitiatingMessage',Val2),
- ?line {ok,_Ret2} = asn1_wrapper:decode('RANAP','InitiatingMessage',Bytes2),
+ {ok,Bytes2} = 'RANAP':encode('InitiatingMessage', Val2),
+ {ok,_Ret2} = 'RANAP':decode('InitiatingMessage', Bytes2),
ok.
-open_type(uper,Val) when is_list(Val) ->
- list_to_binary(Val);
-open_type(_,Val) ->
- Val.
-
param2(Config, Erule) ->
roundtrip2('HandoverRequired',
{'HandoverRequired',
@@ -148,7 +131,7 @@ param2(Config, Erule) ->
{'ProtocolIE-Field',2,-42},
{'ProtocolIE-Field',100,Open100},
{'ProtocolIE-Field',101,Open101}]}} =
- asn1_wrapper:decode('Param2', 'HandoverRequired', Enc),
+ 'Param2':decode('HandoverRequired', Enc),
true = is_binary(Open100),
true = is_binary(Open101),
@@ -160,6 +143,4 @@ param2(Config, Erule) ->
roundtrip2(T, V) ->
- {ok,Enc} = asn1_wrapper:encode('Param2', T, V),
- {ok,V} = asn1_wrapper:decode('Param2', T, Enc),
- Enc.
+ asn1_test_lib:roundtrip_enc('Param2', T, V).
diff --git a/lib/asn1/test/testPrim.erl b/lib/asn1/test/testPrim.erl
index a6e68a9fe0..e07379e634 100644
--- a/lib/asn1/test/testPrim.erl
+++ b/lib/asn1/test/testPrim.erl
@@ -36,8 +36,7 @@ bool(Rules) ->
case Rules of
ber ->
[begin
- {error,{asn1,{encode_boolean,517}}} =
- (catch 'Prim':encode(T, 517))
+ {error,{asn1,{encode_boolean,517}}} = enc_error(T, 517)
end || T <- Types],
ok;
_ ->
@@ -90,12 +89,12 @@ enum(Rules) ->
roundtrip('Enum', monday),
roundtrip('Enum', thursday),
- {error,{asn1,{_,4}}} = (catch 'Prim':encode('Enum', 4)),
+ {error,{asn1,{_,4}}} = enc_error('Enum', 4),
case Rules of
Per when Per =:= per; Per =:= uper ->
- {ok,<<0>>} = 'Prim':encode('SingleEnumVal', true),
- {ok,<<0>>} = 'Prim':encode('SingleEnumValExt', true);
+ <<0>> = roundtrip('SingleEnumVal', true),
+ <<0>> = roundtrip('SingleEnumValExt', true);
ber ->
ok
end,
@@ -128,15 +127,36 @@ null(_Rules) ->
%%==========================================================
%% Null ::= NULL
%%==========================================================
-
- {ok,Bytes1} = asn1_wrapper:encode('Prim','Null',monday),
- {ok,'NULL'} = asn1_wrapper:decode('Prim','Null',lists:flatten(Bytes1)),
+ roundtrip('Null', monday, 'NULL'),
ok.
roundtrip(T, V) ->
- {ok,E} = 'Prim':encode(T, V),
- {ok,V} = 'Prim':decode(T, E),
- E.
+ roundtrip(T, V, V).
+
+roundtrip(Type, Value, ExpectedValue) ->
+ case get(no_ok_wrapper) of
+ false ->
+ asn1_test_lib:roundtrip_enc('Prim', Type, Value, ExpectedValue);
+ true ->
+ M = 'Prim',
+ Enc = M:encode(Type, Value),
+ ExpectedValue = M:decode(Type, Enc),
+ Enc
+ end.
+
+enc_error(T, V) ->
+ case get(no_ok_wrapper) of
+ false ->
+ 'Prim':encode(T, V);
+ true ->
+ try 'Prim':encode(T, V) of
+ _ ->
+ ?t:fail()
+ catch
+ _:Reason ->
+ Reason
+ end
+ end.
real(_Rules) ->
%%==========================================================
@@ -144,67 +164,45 @@ real(_Rules) ->
%%==========================================================
%% Base 2
- ?line {ok,Bytes1} = asn1_wrapper:encode('Real','AngleInRadians',{1,2,1}),
- ?line {ok,{1,2,1}} = asn1_wrapper:decode('Real','AngleInRadians',Bytes1),
-
- ?line {ok,Bytes2} = asn1_wrapper:encode('Real','AngleInRadians',{129,2,1}),
- ?line {ok,{129,2,1}} = asn1_wrapper:decode('Real','AngleInRadians',Bytes2),
-
- ?line {ok,Bytes3} = asn1_wrapper:encode('Real','AngleInRadians',{128,2,1}),
- ?line {ok,{1,2,8}} = asn1_wrapper:decode('Real','AngleInRadians',Bytes3),
-
- ?line {ok,Bytes4} = asn1_wrapper:encode('Real','AngleInRadians',{128,2,-7}),
- ?line {ok,{1,2,0}} = asn1_wrapper:decode('Real','AngleInRadians',Bytes4),
-
- ?line {ok,Bytes5} = asn1_wrapper:encode('Real','AngleInRadians',{16#f1f1f1,2,128}),
- ?line {ok,{16#f1f1f1,2,128}} = asn1_wrapper:decode('Real','AngleInRadians',Bytes5),
+ real_roundtrip('AngleInRadians', {1,2,1}),
+ real_roundtrip('AngleInRadians', {129,2,1}),
+ real_roundtrip('AngleInRadians', {128,2,1}, {1,2,8}),
+ real_roundtrip('AngleInRadians', {128,2,-7}, {1,2,0}),
+ real_roundtrip('AngleInRadians', {16#f1f1f1,2,128}),
%% Base 10, tuple format
- ?line {ok,Bytes6} = asn1_wrapper:encode('Real','AngleInRadians',{1,10,1}),
- ?line {ok,"1.E1"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes6),
-
- ?line {ok,Bytes7} = asn1_wrapper:encode('Real','AngleInRadians',{100,10,1}),
- ?line {ok,"1.E3"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes7),
-
- ?line {ok,Bytes8} = asn1_wrapper:encode('Real','AngleInRadians',{-100,10,1}),
- ?line {ok,"-1.E3"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes8),
-
- ?line {ok,Bytes9} = asn1_wrapper:encode('Real','AngleInRadians',{00002,10,1}),
- ?line {ok,"2.E1"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes9),
-
- ?line {ok,Bytes10} = asn1_wrapper:encode('Real','AngleInRadians',{123000,10,0}),
- ?line {ok,"123.E3"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes10),
-
- ?line {ok,Bytes11} = asn1_wrapper:encode('Real','AngleInRadians',{123456789,10,123456789}),
- ?line {ok,"123456789.E123456789"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes11),
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('Real','AngleInRadians',{-12345,10,-12345}),
- ?line {ok,"-12345.E-12345"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes12),
+ real_roundtrip('AngleInRadians', {1,10,1}, "1.E1"),
+ real_roundtrip('AngleInRadians', {100,10,1}, "1.E3"),
+ real_roundtrip('AngleInRadians', {-100,10,1}, "-1.E3"),
+ real_roundtrip('AngleInRadians', {2,10,1}, "2.E1"),
+ real_roundtrip('AngleInRadians', {123000,10,0}, "123.E3"),
+ real_roundtrip('AngleInRadians', {123456789,10,123456789},
+ "123456789.E123456789" ),
+ real_roundtrip('AngleInRadians', {-12345,10,-12345}, "-12345.E-12345"),
%% Base 10, string format NR3
-
- ?line {ok,Bytes13} = asn1_wrapper:encode('Real','AngleInRadians',"123.123E123"),
- ?line {ok,"123123.E120"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes13),
-
- ?line {ok,Bytes14} = asn1_wrapper:encode('Real','AngleInRadians',"0.0E0"),
- ?line {ok,"0.E+0"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes14),
- ?line {ok,Bytes15} = asn1_wrapper:encode('Real','AngleInRadians',"0.0123"),
- ?line {ok,"123.E-4"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes15),
+ real_roundtrip('AngleInRadians', "123.123E123", "123123.E120"),
+ real_roundtrip('AngleInRadians', "0.0E0", "0.E+0"),
+ real_roundtrip('AngleInRadians', "0.0123", "123.E-4"),
+ real_roundtrip('AngleInRadians', "0", "0.E+0"),
+ real_roundtrip('AngleInRadians', "-123.45", "-12345.E-2"),
+ real_roundtrip('AngleInRadians', "123456789E123456789",
+ "123456789.E123456789"),
+ real_roundtrip('AngleInRadians', "01.000E1", "1.E1"),
+ real_roundtrip('AngleInRadians', "120.0001", "1200001.E-4"),
- ?line {ok,Bytes16} = asn1_wrapper:encode('Real','AngleInRadians',"0"),
- ?line {ok,"0.E+0"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes16),
-
- ?line {ok,Bytes17} = asn1_wrapper:encode('Real','AngleInRadians',"-123.45"),
- ?line {ok,"-12345.E-2"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes17),
-
- ?line {ok,Bytes18} =
- asn1_wrapper:encode('Real','AngleInRadians',"123456789E123456789"),
- ?line {ok,"123456789.E123456789"} =
- asn1_wrapper:decode('Real','AngleInRadians',Bytes18),
+ ok.
- ?line {ok,Bytes19} = asn1_wrapper:encode('Real','AngleInRadians',"01.000E1"),
- ?line {ok,"1.E1"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes19),
+real_roundtrip(T, V) ->
+ real_roundtrip(T, V, V).
- ?line {ok,Bytes20} = asn1_wrapper:encode('Real','AngleInRadians',"120.0001"),
- ?line {ok,"1200001.E-4"} = asn1_wrapper:decode('Real','AngleInRadians',Bytes20).
+real_roundtrip(Type, Value, ExpectedValue) ->
+ case get(no_ok_wrapper) of
+ false ->
+ asn1_test_lib:roundtrip('Real', Type, Value, ExpectedValue);
+ true ->
+ M = 'Real',
+ ExpectedValue = M:decode(Type, M:encode(Type, Value)),
+ ok
+ end.
diff --git a/lib/asn1/test/testPrimExternal.erl b/lib/asn1/test/testPrimExternal.erl
index 65c3c3a31a..07a1de931f 100644
--- a/lib/asn1/test/testPrimExternal.erl
+++ b/lib/asn1/test/testPrimExternal.erl
@@ -24,84 +24,27 @@
-include_lib("test_server/include/test_server.hrl").
external(_Rules) ->
-
-
- ?line {ok,Bytes10} = asn1_wrapper:encode('PrimExternal','NT',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','NT',lists:flatten(Bytes10)),
-
- ?line {ok,Bytes11} = asn1_wrapper:encode('PrimExternal','Imp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','Imp',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('PrimExternal','Exp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','Exp',lists:flatten(Bytes12)),
-
-
- ?line {ok,Bytes13} = asn1_wrapper:encode('PrimExternal','NTNT',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','NTNT',lists:flatten(Bytes13)),
-
- ?line {ok,Bytes14} = asn1_wrapper:encode('PrimExternal','NTImp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','NTImp',lists:flatten(Bytes14)),
-
- ?line {ok,Bytes15} = asn1_wrapper:encode('PrimExternal','NTExp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','NTExp',lists:flatten(Bytes15)),
-
-
- ?line {ok,Bytes16} = asn1_wrapper:encode('PrimExternal','ImpNT',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','ImpNT',lists:flatten(Bytes16)),
-
- ?line {ok,Bytes17} = asn1_wrapper:encode('PrimExternal','ImpImp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','ImpImp',lists:flatten(Bytes17)),
-
- ?line {ok,Bytes18} = asn1_wrapper:encode('PrimExternal','ImpExp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','ImpExp',lists:flatten(Bytes18)),
-
-
- ?line {ok,Bytes19} = asn1_wrapper:encode('PrimExternal','ExpNT',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','ExpNT',lists:flatten(Bytes19)),
-
- ?line {ok,Bytes20} = asn1_wrapper:encode('PrimExternal','ExpImp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','ExpImp',lists:flatten(Bytes20)),
-
- ?line {ok,Bytes21} = asn1_wrapper:encode('PrimExternal','ExpExp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','ExpExp',lists:flatten(Bytes21)),
-
-
-
-
-
- ?line {ok,Bytes31} = asn1_wrapper:encode('PrimExternal','XNTNT',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','XNTNT',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} = asn1_wrapper:encode('PrimExternal','XNTImp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','XNTImp',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes33} = asn1_wrapper:encode('PrimExternal','XNTExp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','XNTExp',lists:flatten(Bytes33)),
-
-
- ?line {ok,Bytes34} = asn1_wrapper:encode('PrimExternal','XImpNT',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','XImpNT',lists:flatten(Bytes34)),
-
- ?line {ok,Bytes35} = asn1_wrapper:encode('PrimExternal','XImpImp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','XImpImp',lists:flatten(Bytes35)),
-
- ?line {ok,Bytes36} = asn1_wrapper:encode('PrimExternal','XImpExp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','XImpExp',lists:flatten(Bytes36)),
-
-
- ?line {ok,Bytes37} = asn1_wrapper:encode('PrimExternal','XExpNT',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','XExpNT',lists:flatten(Bytes37)),
-
- ?line {ok,Bytes38} = asn1_wrapper:encode('PrimExternal','XExpImp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','XExpImp',lists:flatten(Bytes38)),
-
- ?line {ok,Bytes39} = asn1_wrapper:encode('PrimExternal','XExpExp',"kalle"),
- ?line {ok,"kalle"} = asn1_wrapper:decode('PrimExternal','XExpExp',lists:flatten(Bytes39)),
-
-
-
-
-
-
-
-ok.
+ Types = ['NT',
+ 'Imp',
+ 'Exp',
+ 'NTNT',
+ 'NTImp',
+ 'NTExp',
+ 'ImpNT',
+ 'ImpImp',
+ 'ImpExp',
+ 'ExpNT',
+ 'ExpImp',
+ 'ExpExp',
+ 'XNTNT',
+ 'XNTImp',
+ 'XNTExp',
+ 'XImpNT',
+ 'XImpImp',
+ 'XImpExp',
+ 'XExpNT',
+ 'XExpImp',
+ 'XExpExp'],
+ _ = [asn1_test_lib:roundtrip('PrimExternal', T, "kalle") ||
+ T <- Types],
+ ok.
diff --git a/lib/asn1/test/testPrimStrings.erl b/lib/asn1/test/testPrimStrings.erl
index 1762e34599..2fe0780701 100644
--- a/lib/asn1/test/testPrimStrings.erl
+++ b/lib/asn1/test/testPrimStrings.erl
@@ -19,7 +19,7 @@
%%
-module(testPrimStrings).
--export([bit_string/1]).
+-export([bit_string/2]).
-export([octet_string/1]).
-export([numeric_string/1]).
-export([other_strings/1]).
@@ -68,7 +68,7 @@ fragmented_lengths() ->
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].
-bit_string(Rules) ->
+bit_string(Rules, Opts) ->
%%==========================================================
%% Bs1 ::= BIT STRING
@@ -90,9 +90,10 @@ bit_string(Rules) ->
bs_roundtrip('Bs1', [0,1,0,0,1,0]),
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 Rules of
- ber ->
+
+
+ case {Rules,Opts} 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]),
bs_decode('Bs1', <<35,9,3,2,0,234,3,3,7,156,0>>,
@@ -100,7 +101,17 @@ bit_string(Rules) ->
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]);
_ ->
- ok
+ %% DER, PER, UPER
+ consistent_def_enc('BsDef1',
+ [2#111101,
+ [1,0,1,1,1,1],
+ {2,<<2#101111:6,0:2>>},
+ <<2#101111:6>>]),
+ consistent_def_enc('BsDef2',
+ [[1,1,0,1, 1,1,1,0, 1,0,1,0, 1,1,0,1,
+ 1,0,1,1, 1,1,1,0, 1,1,1,0, 1,1,1,1],
+ {0,<<16#DEADBEEF:4/unit:8>>},
+ <<16#DEADBEEF:4/unit:8>>])
end,
@@ -217,6 +228,24 @@ bit_string(Rules) ->
_ -> per_bs_strings()
end.
+consistent_def_enc(Type, Vs) ->
+ M = 'PrimStrings',
+ {ok,Enc} = M:encode(Type, {Type,asn1_DEFAULT}),
+ {ok,Val} = M:decode(Type, Enc),
+
+ %% Ensure that the value has the correct format.
+ case {M:bit_string_format(),Val} of
+ {bitstring,{_,Bs}} when is_bitstring(Bs) -> ok;
+ {compact,{_,{Unused,Bin}}} when is_integer(Unused),
+ is_binary(Bin) -> ok;
+ {legacy,{_,Bs}} when is_list(Bs) -> ok
+ end,
+
+ %% All values should be recognized and encoded as the
+ %% the default value (i.e. not encoded at all).
+ _ = [{ok,Enc} = M:encode(Type, {Type,V}) || V <- Vs],
+ ok.
+
%% 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
@@ -722,14 +751,10 @@ p_roundtrip(Type, Value0) ->
roundtrip(Type, Value).
roundtrip(Type, Value) ->
- {ok,Encoded} = 'PrimStrings':encode(Type, Value),
- {ok,Value} = 'PrimStrings':decode(Type, Encoded),
- ok.
+ roundtrip(Type, Value, Value).
roundtrip(Type, Value, Expected) ->
- {ok,Encoded} = 'PrimStrings':encode(Type, Value),
- {ok,Expected} = 'PrimStrings':decode(Type, Encoded),
- ok.
+ asn1_test_lib:roundtrip('PrimStrings', Type, Value, Expected).
bs_roundtrip(Type, Value) ->
bs_roundtrip(Type, Value, Value).
diff --git a/lib/asn1/test/testSelectionTypes.erl b/lib/asn1/test/testSelectionTypes.erl
index 6d1641388f..6d060321da 100644
--- a/lib/asn1/test/testSelectionTypes.erl
+++ b/lib/asn1/test/testSelectionTypes.erl
@@ -18,19 +18,16 @@
%%
%%
-module(testSelectionTypes).
-
-export([test/0]).
-include_lib("test_server/include/test_server.hrl").
test() ->
Val = ["PrintableString","PrintableString","PrintableString"],
- ?line {ok,Bin}=asn1_wrapper:encode('SelectionType','MendeleyevTable',Val),
- ?line {ok,Val} = asn1_wrapper:decode('SelectionType','MendeleyevTable',Bin),
-
- ?line Val2 = ['SelectionType':einsteinium()],
- ?line ["Es"] = Val2,
-
- ?line {ok,Bin2}=asn1_wrapper:encode('SelectionType','MendeleyevTable',Val2),
- ?line {ok,Val2} = asn1_wrapper:decode('SelectionType','MendeleyevTable',Bin2).
+ ["Es"] = Val2 = ['SelectionType':einsteinium()],
+ roundtrip('MendeleyevTable', Val),
+ roundtrip('MendeleyevTable', Val2),
+ ok.
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SelectionType', T, V).
diff --git a/lib/asn1/test/testSeq2738.erl b/lib/asn1/test/testSeq2738.erl
index cddfe4b311..9c059f2fc9 100644
--- a/lib/asn1/test/testSeq2738.erl
+++ b/lib/asn1/test/testSeq2738.erl
@@ -18,27 +18,16 @@
%%
%%
-module(testSeq2738).
-
-export([main/1]).
-include_lib("test_server/include/test_server.hrl").
-%-record('SeqOpt',{int, opt = asn1_NOVALUE}).
-record('SeqOptFake',{int, opt = asn1_NOVALUE}).
-%-record('OptSeq',{int=17}).
-record('OptSeqFake',{bool = false}).
-
-
-
main(_Rules) ->
-
- ?line {ok,Bytes} =
- asn1_wrapper:encode('Seq2738','SeqOptFake',
- #'SeqOptFake'{int = 10,
- opt = #'OptSeqFake'{}}),
- ?line {ok,#'SeqOptFake'{int=10,opt=#'OptSeqFake'{bool=false}}} =
- asn1_wrapper:decode('Seq2738','SeqOptFake',lists:flatten(Bytes)),
- ?line {error,_} =
- asn1_wrapper:decode('Seq2738','SeqOpt',lists:flatten(Bytes)),
+ Enc = asn1_test_lib:roundtrip_enc('Seq2738',
+ 'SeqOptFake',
+ #'SeqOptFake'{int=10,opt=#'OptSeqFake'{}}),
+ {error,_} = 'Seq2738':decode('SeqOpt', Enc),
ok.
diff --git a/lib/asn1/test/testSeqDefault.erl b/lib/asn1/test/testSeqDefault.erl
index a772b749bd..22c1b7ee3a 100644
--- a/lib/asn1/test/testSeqDefault.erl
+++ b/lib/asn1/test/testSeqDefault.erl
@@ -33,148 +33,64 @@
-record('SeqDef3',{bool3 = asn1_DEFAULT, seq3 = asn1_DEFAULT, int3 = asn1_DEFAULT}).
-record('SeqDef3Imp',{bool3 = asn1_DEFAULT, seq3 = asn1_DEFAULT, int3 = asn1_DEFAULT}).
-record('SeqDef3Exp',{bool3 = asn1_DEFAULT, seq3 = asn1_DEFAULT, int3 = asn1_DEFAULT}).
--record('SeqIn',{boolIn, intIn}).
+-record('SeqIn',{boolIn = asn1_NOVALUE, intIn = 12}).
main(_Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SeqDefault','SeqDef1',#'SeqDef1'{bool1 = true,
- int1 = 15,
- seq1 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqDef1',true,15,{'SeqIn',true,66}}} =
- asn1_wrapper:decode('SeqDefault','SeqDef1',lists:flatten(Bytes11)),
-
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('SeqDefault','SeqDef1',#'SeqDef1'{int1 = 15}),
- ?line {ok,{'SeqDef1',true,15,{'SeqIn',asn1_NOVALUE,12}}} =
- asn1_wrapper:decode('SeqDefault','SeqDef1',lists:flatten(Bytes12)),
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SeqDefault','SeqDef2',#'SeqDef2'{bool2 = true,
- int2 = 15,
- seq2 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqDef2',{'SeqIn',true,66},true,15}} =
- asn1_wrapper:decode('SeqDefault','SeqDef2',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('SeqDefault','SeqDef2',#'SeqDef2'{int2 = 15}),
- ?line {ok,{'SeqDef2',{'SeqIn',asn1_NOVALUE,12},true,15}} =
- asn1_wrapper:decode('SeqDefault','SeqDef2',lists:flatten(Bytes22)),
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SeqDefault','SeqDef3',#'SeqDef3'{bool3 = true,
- int3 = 15,
- seq3 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqDef3',true,{'SeqIn',true,66},15}} =
- asn1_wrapper:decode('SeqDefault','SeqDef3',lists:flatten(Bytes31)),
-
-
- ?line {ok,Bytes32} = asn1_wrapper:encode('SeqDefault','SeqDef3',#'SeqDef3'{int3 = 15}),
- ?line {ok,{'SeqDef3',true,{'SeqIn',asn1_NOVALUE,12},15}} =
- asn1_wrapper:decode('SeqDefault','SeqDef3',lists:flatten(Bytes32)),
-
-
-
-
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SeqDefault','SeqDef1Imp',#'SeqDef1Imp'{bool1 = true,
- int1 = 15,
- seq1 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqDef1Imp',true,15,{'SeqIn',true,66}}} =
- asn1_wrapper:decode('SeqDefault','SeqDef1Imp',lists:flatten(Bytes41)),
-
-
- ?line {ok,Bytes42} = asn1_wrapper:encode('SeqDefault','SeqDef1Imp',#'SeqDef1Imp'{int1 = 15}),
- ?line {ok,{'SeqDef1Imp',true,15,{'SeqIn',asn1_NOVALUE,12}}} =
- asn1_wrapper:decode('SeqDefault','SeqDef1Imp',lists:flatten(Bytes42)),
-
-
- ?line {ok,Bytes51} =
- asn1_wrapper:encode('SeqDefault','SeqDef2Imp',#'SeqDef2Imp'{bool2 = true,
- int2 = 15,
- seq2 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqDef2Imp',{'SeqIn',true,66},true,15}} =
- asn1_wrapper:decode('SeqDefault','SeqDef2Imp',lists:flatten(Bytes51)),
-
-
- ?line {ok,Bytes52} = asn1_wrapper:encode('SeqDefault','SeqDef2Imp',#'SeqDef2Imp'{int2 = 15}),
- ?line {ok,{'SeqDef2Imp',{'SeqIn',asn1_NOVALUE,12},true,15}} =
- asn1_wrapper:decode('SeqDefault','SeqDef2Imp',lists:flatten(Bytes52)),
-
-
-
- ?line {ok,Bytes61} =
- asn1_wrapper:encode('SeqDefault','SeqDef3Imp',#'SeqDef3Imp'{bool3 = true,
- int3 = 15,
- seq3 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqDef3Imp',true,{'SeqIn',true,66},15}} =
- asn1_wrapper:decode('SeqDefault','SeqDef3Imp',lists:flatten(Bytes61)),
-
-
- ?line {ok,Bytes62} = asn1_wrapper:encode('SeqDefault','SeqDef3Imp',#'SeqDef3Imp'{int3 = 15}),
- ?line {ok,{'SeqDef3Imp',true,{'SeqIn',asn1_NOVALUE,12},15}} =
- asn1_wrapper:decode('SeqDefault','SeqDef3Imp',lists:flatten(Bytes62)),
-
-
-
-
-
-
- ?line {ok,Bytes71} =
- asn1_wrapper:encode('SeqDefault','SeqDef1Exp',#'SeqDef1Exp'{bool1 = true,
- int1 = 15,
- seq1 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqDef1Exp',true,15,{'SeqIn',true,66}}} =
- asn1_wrapper:decode('SeqDefault','SeqDef1Exp',lists:flatten(Bytes71)),
-
-
- ?line {ok,Bytes72} = asn1_wrapper:encode('SeqDefault','SeqDef1Exp',#'SeqDef1Exp'{int1 = 15}),
- ?line {ok,{'SeqDef1Exp',true,15,{'SeqIn',asn1_NOVALUE,12}}} =
- asn1_wrapper:decode('SeqDefault','SeqDef1Exp',lists:flatten(Bytes72)),
-
-
- ?line {ok,Bytes81} =
- asn1_wrapper:encode('SeqDefault','SeqDef2Exp',#'SeqDef2Exp'{bool2 = true,
- int2 = 15,
- seq2 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqDef2Exp',{'SeqIn',true,66},true,15}} =
- asn1_wrapper:decode('SeqDefault','SeqDef2Exp',lists:flatten(Bytes81)),
-
-
- ?line {ok,Bytes82} = asn1_wrapper:encode('SeqDefault','SeqDef2Exp',#'SeqDef2Exp'{int2 = 15,
- bool2 = true}),
- ?line {ok,{'SeqDef2Exp',{'SeqIn',asn1_NOVALUE,12},true,15}} =
- asn1_wrapper:decode('SeqDefault','SeqDef2Exp',lists:flatten(Bytes82)),
-
-
-
- ?line {ok,Bytes91} =
- asn1_wrapper:encode('SeqDefault','SeqDef3Exp',#'SeqDef3Exp'{bool3 = true,
- int3 = 15,
- seq3 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqDef3Exp',true,{'SeqIn',true,66},15}} =
- asn1_wrapper:decode('SeqDefault','SeqDef3Exp',lists:flatten(Bytes91)),
-
-
- ?line {ok,Bytes92} = asn1_wrapper:encode('SeqDefault','SeqDef3Exp',#'SeqDef3Exp'{int3 = 15}),
- ?line {ok,{'SeqDef3Exp',true,{'SeqIn',asn1_NOVALUE,12},15}} =
- asn1_wrapper:decode('SeqDefault','SeqDef3Exp',lists:flatten(Bytes92)),
-
-
-
-
+ roundtrip('SeqDef1', #'SeqDef1'{bool1=true,int1=15,seq1=#'SeqIn'{boolIn=true,intIn=66}}),
+ roundtrip('SeqDef1',
+ #'SeqDef1'{bool1=asn1_DEFAULT,int1=15,seq1=asn1_DEFAULT},
+ #'SeqDef1'{bool1=true,int1=15,seq1=#'SeqIn'{}}),
+
+ roundtrip('SeqDef2', #'SeqDef2'{seq2=#'SeqIn'{boolIn=true,intIn=66},bool2=true,int2=15}),
+ roundtrip('SeqDef2',
+ #'SeqDef2'{seq2=asn1_DEFAULT,bool2=asn1_DEFAULT,int2=15},
+ #'SeqDef2'{seq2=#'SeqIn'{},bool2=true,int2=15}),
+
+ roundtrip('SeqDef3', #'SeqDef3'{bool3=true,seq3=#'SeqIn'{boolIn=true,intIn=66},int3=15}),
+ roundtrip('SeqDef3',
+ #'SeqDef3'{bool3=asn1_DEFAULT,seq3=asn1_DEFAULT,int3=15},
+ #'SeqDef3'{bool3=true,seq3=#'SeqIn'{},int3=15}),
+
+ roundtrip('SeqDef1Imp', #'SeqDef1Imp'{bool1=true,int1=15,
+ seq1=#'SeqIn'{boolIn=true,intIn=66}}),
+ roundtrip('SeqDef1Imp',
+ #'SeqDef1Imp'{bool1=asn1_DEFAULT,int1=15,seq1=asn1_DEFAULT},
+ #'SeqDef1Imp'{bool1=true,int1=15,seq1=#'SeqIn'{}}),
+
+ roundtrip('SeqDef2Imp', #'SeqDef2Imp'{seq2=#'SeqIn'{boolIn=true,intIn=66},
+ bool2=true,int2=15}),
+ roundtrip('SeqDef2Imp',
+ #'SeqDef2Imp'{seq2=asn1_DEFAULT,bool2=asn1_DEFAULT,int2=15},
+ #'SeqDef2Imp'{seq2=#'SeqIn'{},bool2=true,int2=15}),
+
+ roundtrip('SeqDef3Imp',
+ #'SeqDef3Imp'{bool3=true,seq3=#'SeqIn'{boolIn=true,intIn=66},int3=15}),
+ roundtrip('SeqDef3Imp',
+ #'SeqDef3Imp'{bool3=asn1_DEFAULT,seq3=asn1_DEFAULT,int3=15},
+ #'SeqDef3Imp'{bool3=true,seq3=#'SeqIn'{},int3=15}),
+
+ roundtrip('SeqDef1Exp',
+ #'SeqDef1Exp'{bool1=true,int1=15,seq1=#'SeqIn'{boolIn=true,intIn=66}}),
+ roundtrip('SeqDef1Exp',
+ #'SeqDef1Exp'{bool1=asn1_DEFAULT,int1=15,seq1=asn1_DEFAULT},
+ #'SeqDef1Exp'{bool1=true,int1=15,seq1=#'SeqIn'{}}),
+
+ roundtrip('SeqDef2Exp', #'SeqDef2Exp'{seq2=#'SeqIn'{boolIn=true,intIn=66},
+ bool2=true,int2=15}),
+ roundtrip('SeqDef2Exp',
+ #'SeqDef2Exp'{seq2=asn1_DEFAULT,bool2=true,int2=15},
+ #'SeqDef2Exp'{seq2=#'SeqIn'{},bool2=true,int2=15}),
+
+ roundtrip('SeqDef3Exp',
+ #'SeqDef3Exp'{bool3=true,seq3=#'SeqIn'{boolIn=true,intIn=66},int3=15}),
+ roundtrip('SeqDef3Exp',
+ #'SeqDef3Exp'{bool3=asn1_DEFAULT,seq3=asn1_DEFAULT,int3=15},
+ #'SeqDef3Exp'{bool3=true,seq3=#'SeqIn'{},int3=15}),
ok.
+
+roundtrip(Type, Value) ->
+ roundtrip(Type, Value, Value).
+
+roundtrip(Type, Value, ExpectedValue) ->
+ asn1_test_lib:roundtrip('SeqDefault', Type, Value, ExpectedValue).
diff --git a/lib/asn1/test/testSeqExtension.erl b/lib/asn1/test/testSeqExtension.erl
index b996634996..8473459c36 100644
--- a/lib/asn1/test/testSeqExtension.erl
+++ b/lib/asn1/test/testSeqExtension.erl
@@ -108,18 +108,14 @@ main(Erule, DataDir, Opts) ->
ok.
roundtrip(Type, Value) ->
- {ok,Encoded} = 'SeqExtension':encode(Type, Value),
- {ok,Value} = 'SeqExtension':decode(Type, Encoded),
- ok.
+ asn1_test_lib:roundtrip('SeqExtension', Type, Value).
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.
+ asn1_test_lib:roundtrip_enc('SeqExtension2', Type, Value).
v(ber, 'SeqExt66') -> "30049F41 017D";
v(per, 'SeqExt66') -> "C0420000 00000000 00004001 FA";
diff --git a/lib/asn1/test/testSeqExternal.erl b/lib/asn1/test/testSeqExternal.erl
index b89b98d3fa..a8e0902244 100644
--- a/lib/asn1/test/testSeqExternal.erl
+++ b/lib/asn1/test/testSeqExternal.erl
@@ -20,121 +20,38 @@
-module(testSeqExternal).
-include("External.hrl").
--export([compile/3]).
-export([main/1]).
-include_lib("test_server/include/test_server.hrl").
-
-record('SeqXSet1',{set, bool, int}).
-record('SeqXSet2',{bool, set, int}).
-record('SeqXSet3',{bool, int, set}).
-%-record('NT',{os, bool}).
-%-record('Imp',{os, bool}).
-%-record('Exp',{os, bool}).
-
-
-compile(Config,Rules,Options) ->
-
- ?line DataDir = ?config(data_dir,Config),
- ?line OutDir = ?config(priv_dir,Config),
- ?line true = code:add_patha(?config(priv_dir,Config)),
- ?line ok = asn1ct:compile(DataDir ++ "SeqExternal",
- [Rules,{outdir,OutDir}]++Options).
-
-
main(_Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SeqExternal','XNTNT',#'XSeqNT'{bool = true, os = "kalle"}),
- ?line {ok,{'XSeqNT',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SeqExternal','XNTNT',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SeqExternal','XImpNT',#'XSeqNT'{bool = true, os = "kalle"}),
- ?line {ok,{'XSeqNT',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SeqExternal','XImpNT',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SeqExternal','XExpNT',#'XSeqNT'{bool = true, os = "kalle"}),
- ?line {ok,{'XSeqNT',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SeqExternal','XExpNT',lists:flatten(Bytes13)),
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SeqExternal','XNTImp',#'XSeqImp'{bool = true, os = "kalle"}),
- ?line {ok,{'XSeqImp',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SeqExternal','XNTImp',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SeqExternal','XImpImp',#'XSeqImp'{bool = true, os = "kalle"}),
- ?line {ok,{'XSeqImp',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SeqExternal','XImpImp',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('SeqExternal','XExpImp',#'XSeqImp'{bool = true, os = "kalle"}),
- ?line {ok,{'XSeqImp',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SeqExternal','XExpImp',lists:flatten(Bytes23)),
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SeqExternal','XNTExp',#'XSeqExp'{bool = true, os = "kalle"}),
- ?line {ok,{'XSeqExp',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SeqExternal','XNTExp',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} =
- asn1_wrapper:encode('SeqExternal','XImpExp',#'XSeqExp'{bool = true, os = "kalle"}),
- ?line {ok,{'XSeqExp',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SeqExternal','XImpExp',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes33} =
- asn1_wrapper:encode('SeqExternal','XExpExp',#'XSeqExp'{bool = true, os = "kalle"}),
- ?line {ok,{'XSeqExp',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SeqExternal','XExpExp',lists:flatten(Bytes33)),
-
-
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SeqExternal','SeqXSet1',
- #'SeqXSet1'{bool = true,
- int = 66,
- set = #'XSet1'{bool1 = true,
- int1 = 77,
- set1 = #'XSetIn'{boolIn = false,
- intIn = 88}}}),
- ?line {ok,{'SeqXSet1',{'XSet1',true,77,{'XSetIn',false,88}},true,66}} =
- asn1_wrapper:decode('SeqExternal','SeqXSet1',lists:flatten(Bytes41)),
-
-
-
- ?line {ok,Bytes42} =
- asn1_wrapper:encode('SeqExternal','SeqXSet2',
- #'SeqXSet2'{bool = true,
- int = 66,
- set = #'XSet1'{bool1 = true,
- int1 = 77,
- set1 = #'XSetIn'{boolIn = false,
- intIn = 88}}}),
- ?line {ok,{'SeqXSet2',true,{'XSet1',true,77,{'XSetIn',false,88}},66}} =
- asn1_wrapper:decode('SeqExternal','SeqXSet2',lists:flatten(Bytes42)),
-
- ?line {ok,Bytes43} =
- asn1_wrapper:encode('SeqExternal','SeqXSet3',
- #'SeqXSet3'{bool = true,
- int = 66,
- set = #'XSet1'{bool1 = true,
- int1 = 77,
- set1 = #'XSetIn'{boolIn = false,
- intIn = 88}}}),
- ?line {ok,{'SeqXSet3',true,66,{'XSet1',true,77,{'XSetIn',false,88}}}} =
- asn1_wrapper:decode('SeqExternal','SeqXSet3',lists:flatten(Bytes43)),
-
-
-
-
+ roundtrip('XNTNT', #'XSeqNT'{os="kalle",bool=true}),
+ roundtrip('XImpNT', #'XSeqNT'{os="kalle",bool=true}),
+ roundtrip('XExpNT', #'XSeqNT'{os="kalle",bool=true}),
+ roundtrip('XNTImp', #'XSeqImp'{os="kalle",bool=true}),
+ roundtrip('XImpImp', #'XSeqImp'{os="kalle",bool=true}),
+ roundtrip('XExpImp', #'XSeqImp'{os="kalle",bool=true}),
+ roundtrip('XNTExp', #'XSeqExp'{os="kalle",bool=true}),
+ roundtrip('XImpExp', #'XSeqExp'{os="kalle",bool=true}),
+ roundtrip('XExpExp', #'XSeqExp'{os="kalle",bool=true}),
+ roundtrip('SeqXSet1',
+ #'SeqXSet1'{set=#'XSet1'{bool1=true,int1=77,
+ set1=#'XSetIn'{boolIn=false,intIn=88}},
+ bool=true,int=66}),
+ roundtrip('SeqXSet2',
+ #'SeqXSet2'{bool=true,
+ set=#'XSet1'{bool1=true,int1=77,
+ set1=#'XSetIn'{boolIn=false,intIn=88}},
+ int=66}),
+ roundtrip('SeqXSet3',
+ #'SeqXSet3'{bool=true,int=66,
+ set=#'XSet1'{bool1=true,int1=77,
+ set1=#'XSetIn'{boolIn=false,intIn=88}}}),
ok.
-
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SeqExternal', T, V).
diff --git a/lib/asn1/test/testSeqIndefinite.erl b/lib/asn1/test/testSeqIndefinite.erl
deleted file mode 100644
index c7b8aba523..0000000000
--- a/lib/asn1/test/testSeqIndefinite.erl
+++ /dev/null
@@ -1,48 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-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%
-%%
-%%
--module(testSeqIndefinite).
-
--export([main/1]).
-
--include_lib("test_server/include/test_server.hrl").
-
-main(per) -> ok;
-main(ber) ->
-
- %% normal encoding
- B = [48,20,1,1,255,48,9,1,1,255,2,4,251,35,238,194,2,4,251,55,236,161],
- %% indefinite length encoding
- Bi = [48,22,1,1,255,48,128,1,1,255,2,4,251,35,238,194,0,0,2,4,251,55,236,161],
- %% the value which is encoded
- V = {'SeqS3',true,{'SeqS3_seqS3',true,-81531198},-80221023},
- ?line {ok,V} = asn1_wrapper:decode('SeqSetIndefinite','SeqS3',B),
- ?line {ok,V} = asn1_wrapper:decode('SeqSetIndefinite','SeqS3',Bi),
-
- %% normal encoding but with unknown extension component
- _Be = [48,23,1,1,255,48,12,1,1,255,2,4,251,35,238,194,1,1,255,2,4,251,55,236,161],
- %% indefinite length encoding but with unknown extension component
- _Bei = [48,25,1,1,255,48,128,1,1,255,2,4,251,35,238,194,1,1,255,0,0,2,4,251,55,236,161],
-
- ?line {ok,V} = asn1_wrapper:decode('SeqSetIndefinite','SeqS3',B),
- ?line {ok,V} = asn1_wrapper:decode('SeqSetIndefinite','SeqS3',Bi),
- ok.
-
-
-
diff --git a/lib/asn1/test/testSeqOf.erl b/lib/asn1/test/testSeqOf.erl
index c50cc27f6f..7f8f4079b4 100644
--- a/lib/asn1/test/testSeqOf.erl
+++ b/lib/asn1/test/testSeqOf.erl
@@ -149,15 +149,9 @@ roundtrip(T, V) ->
roundtrip(T, V, V).
roundtrip(Type, Val, Expected) ->
- M = 'SeqOf',
- {ok,Enc} = M:encode(Type, Val),
- {ok,Expected} = M:decode(Type, Enc),
- ok.
+ asn1_test_lib:roundtrip('SeqOf', Type, Val, Expected).
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),
+ Enc = asn1_test_lib:roundtrip_enc('XSeqOf', T1, Val),
+ Enc = asn1_test_lib:roundtrip_enc('XSeqOf', T2, Val),
ok.
diff --git a/lib/asn1/test/testSeqOfCho.erl b/lib/asn1/test/testSeqOfCho.erl
index 5b83c8bf21..f749845bb9 100644
--- a/lib/asn1/test/testSeqOfCho.erl
+++ b/lib/asn1/test/testSeqOfCho.erl
@@ -31,117 +31,45 @@
-record('SeqOfChoEmbOpt_SEQOF',{bool1, int1, seq1 = asn1_NOVALUE}).
main(_Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SeqOfCho','SeqChoDef',#'SeqChoDef'{bool1 = true,
- int1 = 17}),
- ?line {ok,{'SeqChoDef',true,17,[]}} =
- asn1_wrapper:decode('SeqOfCho','SeqChoDef',lists:flatten(Bytes11)),
-
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SeqOfCho','SeqChoDef',#'SeqChoDef'{bool1 = true,
- int1 = 17,
- seq1 = [{boolIn,true},
- {intIn,25}]}),
- ?line {ok,{'SeqChoDef',true,17,[{boolIn,true},{intIn,25}]}} =
- asn1_wrapper:decode('SeqOfCho','SeqChoDef',lists:flatten(Bytes12)),
-
-
-
- ?line {ok,Bytes15} =
- asn1_wrapper:encode('SeqOfCho','SeqChoOpt',#'SeqChoOpt'{bool1 = true,
- int1 = 17}),
- ?line {ok,{'SeqChoOpt',true,17,asn1_NOVALUE}} =
- asn1_wrapper:decode('SeqOfCho','SeqChoOpt',lists:flatten(Bytes15)),
-
-
- ?line {ok,Bytes16} =
- asn1_wrapper:encode('SeqOfCho','SeqChoOpt',#'SeqChoOpt'{bool1 = true,
- int1 = 17,
- seq1 = [{boolIn,true},
- {intIn,25}]}),
- ?line {ok,{'SeqChoOpt',true,17,[{boolIn,true},{intIn,25}]}} =
- asn1_wrapper:decode('SeqOfCho','SeqChoOpt',lists:flatten(Bytes16)),
-
-
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SeqOfCho','SeqChoEmbDef',#'SeqChoEmbDef'{bool1 = true,
- int1 = 17}),
- ?line {ok,{'SeqChoEmbDef',true,17,[]}} =
- asn1_wrapper:decode('SeqOfCho','SeqChoEmbDef',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SeqOfCho','SeqChoEmbDef',#'SeqChoEmbDef'{bool1 = true,
- int1 = 17,
- seq1 = [{boolIn,true},
- {intIn,25}]}),
- ?line {ok,{'SeqChoEmbDef',true,17,[{boolIn,true},{intIn,25}]}} =
- asn1_wrapper:decode('SeqOfCho','SeqChoEmbDef',lists:flatten(Bytes22)),
-
-
-
- ?line {ok,Bytes25} =
- asn1_wrapper:encode('SeqOfCho','SeqChoEmbOpt',#'SeqChoEmbOpt'{bool1 = true,
- int1 = 17}),
- ?line {ok,{'SeqChoEmbOpt',true,17,asn1_NOVALUE}} =
- asn1_wrapper:decode('SeqOfCho','SeqChoEmbOpt',lists:flatten(Bytes25)),
-
-
- ?line {ok,Bytes26} =
- asn1_wrapper:encode('SeqOfCho','SeqChoEmbOpt',#'SeqChoEmbOpt'{bool1 = true,
- int1 = 17,
- seq1 = [{boolIn,true},
- {intIn,25}]}),
- ?line {ok,{'SeqChoEmbOpt',true,17,[{boolIn,true},{intIn,25}]}} =
- asn1_wrapper:decode('SeqOfCho','SeqChoEmbOpt',lists:flatten(Bytes26)),
-
-
-
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SeqOfCho','SeqOfChoEmbDef',[#'SeqOfChoEmbDef_SEQOF'{bool1 = true,
- int1 = 17}]),
- ?line {ok,[{'SeqOfChoEmbDef_SEQOF',true,17,[]}]} =
- asn1_wrapper:decode('SeqOfCho','SeqOfChoEmbDef',lists:flatten(Bytes31)),
-
-
- ?line {ok,Bytes32} =
- asn1_wrapper:encode('SeqOfCho','SeqOfChoEmbDef',
- [#'SeqOfChoEmbDef_SEQOF'{bool1 = true,
- int1 = 17,
- seq1 = [{boolIn,true},
- {intIn,25}]}]),
- ?line {ok,[{'SeqOfChoEmbDef_SEQOF',true,17,[{boolIn,true},{intIn,25}]}]} =
- asn1_wrapper:decode('SeqOfCho','SeqOfChoEmbDef',lists:flatten(Bytes32)),
-
-
-
- ?line {ok,Bytes35} =
- asn1_wrapper:encode('SeqOfCho','SeqOfChoEmbOpt',[#'SeqOfChoEmbOpt_SEQOF'{bool1 = true,
- int1 = 17}]),
- ?line {ok,[{'SeqOfChoEmbOpt_SEQOF',true,17,asn1_NOVALUE}]} =
- asn1_wrapper:decode('SeqOfCho','SeqOfChoEmbOpt',lists:flatten(Bytes35)),
-
-
- ?line {ok,Bytes36} =
- asn1_wrapper:encode('SeqOfCho','SeqOfChoEmbOpt',
- [#'SeqOfChoEmbOpt_SEQOF'{bool1 = true,
- int1 = 17,
- seq1 = [{boolIn,true},
- {intIn,25}]}]),
- ?line {ok,[{'SeqOfChoEmbOpt_SEQOF',true,17,[{boolIn,true},{intIn,25}]}]} =
- asn1_wrapper:decode('SeqOfCho','SeqOfChoEmbOpt',lists:flatten(Bytes36)),
-
-
-
-
+ roundtrip('SeqChoDef',
+ #'SeqChoDef'{bool1=true,int1=17,seq1=asn1_DEFAULT},
+ #'SeqChoDef'{bool1=true,int1=17,seq1=[]}),
+ roundtrip('SeqChoDef',
+ #'SeqChoDef'{bool1=true,int1=17,
+ seq1=[{boolIn,true},{intIn,25}]}),
+ roundtrip('SeqChoOpt',
+ #'SeqChoOpt'{bool1=true,int1=17,seq1=asn1_NOVALUE}),
+ roundtrip('SeqChoOpt',
+ #'SeqChoOpt'{bool1=true,int1=17,
+ seq1=[{boolIn,true},{intIn,25}]}),
+
+ roundtrip('SeqChoEmbDef',
+ #'SeqChoEmbDef'{bool1=true,int1=17,seq1=asn1_DEFAULT},
+ #'SeqChoEmbDef'{bool1=true,int1=17,seq1=[]}),
+ roundtrip('SeqChoEmbDef',
+ #'SeqChoEmbDef'{bool1=true,int1=17,
+ seq1=[{boolIn,true},{intIn,25}]}),
+ roundtrip('SeqChoEmbOpt',
+ #'SeqChoEmbOpt'{bool1=true,int1=17,seq1=asn1_NOVALUE}),
+ roundtrip('SeqChoEmbOpt',
+ #'SeqChoEmbOpt'{bool1=true,int1=17,
+ seq1=[{boolIn,true},{intIn,25}]}),
+
+ roundtrip('SeqOfChoEmbDef',
+ [#'SeqOfChoEmbDef_SEQOF'{bool1=true,int1=17,seq1=asn1_DEFAULT}],
+ [#'SeqOfChoEmbDef_SEQOF'{bool1=true,int1=17,seq1=[]}]),
+ roundtrip('SeqOfChoEmbDef',
+ [#'SeqOfChoEmbDef_SEQOF'{bool1=true,int1=17,
+ seq1=[{boolIn,true},{intIn,25}]}]),
+ roundtrip('SeqOfChoEmbOpt',
+ [#'SeqOfChoEmbOpt_SEQOF'{bool1=true,int1=17,seq1=asn1_NOVALUE}]),
+ roundtrip('SeqOfChoEmbOpt',
+ [#'SeqOfChoEmbOpt_SEQOF'{bool1=true,int1=17,
+ seq1=[{boolIn,true},{intIn,25}]}]),
ok.
+roundtrip(Type, Value) ->
+ roundtrip(Type, Value, Value).
+roundtrip(Type, Value, ExpectedValue) ->
+ asn1_test_lib:roundtrip('SeqOfCho', Type, Value, ExpectedValue).
diff --git a/lib/asn1/test/testSeqOfExternal.erl b/lib/asn1/test/testSeqOfExternal.erl
index 4c4c9e2b0f..2e60f441c1 100644
--- a/lib/asn1/test/testSeqOfExternal.erl
+++ b/lib/asn1/test/testSeqOfExternal.erl
@@ -18,9 +18,6 @@
%%
%%
-module(testSeqOfExternal).
-
-
--export([compile/3]).
-export([main/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -30,142 +27,53 @@
-record('Imp',{os, bool}).
-record('Exp',{os, bool}).
-
-
-compile(Config,Rules,Options) ->
-
- ?line DataDir = ?config(data_dir,Config),
- ?line OutDir = ?config(priv_dir,Config),
- ?line true = code:add_patha(?config(priv_dir,Config)),
- ?line ok = asn1ct:compile(DataDir ++ "SeqOfExternal",[Rules,{outdir,OutDir}]++Options).
-
-
-
main(_Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SeqOfExternal','NTNT',[#'NT'{bool = true, os = "kalle"},
- #'NT'{bool = true, os = "kalle"}]),
- ?line {ok,[{'NT',[107,97,108,108,101],true},{'NT',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','NTNT',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SeqOfExternal','ImpNT',[#'NT'{bool = true, os = "kalle"},
- #'NT'{bool = true, os = "kalle"}]),
- ?line {ok,[{'NT',[107,97,108,108,101],true},{'NT',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','ImpNT',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SeqOfExternal','ExpNT',[#'NT'{bool = true, os = "kalle"},
- #'NT'{bool = true, os = "kalle"}]),
- ?line {ok,[{'NT',[107,97,108,108,101],true},{'NT',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','ExpNT',lists:flatten(Bytes13)),
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SeqOfExternal','NTImp',[#'Imp'{bool = true, os = "kalle"},
- #'Imp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'Imp',[107,97,108,108,101],true},{'Imp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','NTImp',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SeqOfExternal','ImpImp',[#'Imp'{bool = true, os = "kalle"},
- #'Imp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'Imp',[107,97,108,108,101],true},{'Imp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','ImpImp',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('SeqOfExternal','ExpImp',[#'Imp'{bool = true, os = "kalle"},
- #'Imp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'Imp',[107,97,108,108,101],true},{'Imp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','ExpImp',lists:flatten(Bytes23)),
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SeqOfExternal','NTExp',[#'Exp'{bool = true, os = "kalle"},
- #'Exp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'Exp',[107,97,108,108,101],true},{'Exp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','NTExp',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} =
- asn1_wrapper:encode('SeqOfExternal','ImpExp',[#'Exp'{bool = true, os = "kalle"},
- #'Exp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'Exp',[107,97,108,108,101],true},{'Exp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','ImpExp',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes33} =
- asn1_wrapper:encode('SeqOfExternal','ExpExp',[#'Exp'{bool = true, os = "kalle"},
- #'Exp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'Exp',[107,97,108,108,101],true},{'Exp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','ExpExp',lists:flatten(Bytes33)),
-
-
-
-
-
-
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SeqOfExternal','XNTNT',[#'XSeqNT'{bool = true, os = "kalle"},
- #'XSeqNT'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSeqNT',[107,97,108,108,101],true},{'XSeqNT',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','XNTNT',lists:flatten(Bytes41)),
-
- ?line {ok,Bytes42} =
- asn1_wrapper:encode('SeqOfExternal','XImpNT',[#'XSeqNT'{bool = true, os = "kalle"},
- #'XSeqNT'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSeqNT',[107,97,108,108,101],true},{'XSeqNT',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','XImpNT',lists:flatten(Bytes42)),
-
- ?line {ok,Bytes43} =
- asn1_wrapper:encode('SeqOfExternal','XExpNT',[#'XSeqNT'{bool = true, os = "kalle"},
- #'XSeqNT'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSeqNT',[107,97,108,108,101],true},{'XSeqNT',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','XExpNT',lists:flatten(Bytes43)),
-
-
-
- ?line {ok,Bytes51} =
- asn1_wrapper:encode('SeqOfExternal','XNTImp',[#'XSeqImp'{bool = true, os = "kalle"},
- #'XSeqImp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSeqImp',[107,97,108,108,101],true},{'XSeqImp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','XNTImp',lists:flatten(Bytes51)),
-
- ?line {ok,Bytes52} =
- asn1_wrapper:encode('SeqOfExternal','XImpImp',[#'XSeqImp'{bool = true, os = "kalle"},
- #'XSeqImp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSeqImp',[107,97,108,108,101],true},{'XSeqImp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','XImpImp',lists:flatten(Bytes52)),
-
- ?line {ok,Bytes53} =
- asn1_wrapper:encode('SeqOfExternal','XExpImp',[#'XSeqImp'{bool = true, os = "kalle"},
- #'XSeqImp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSeqImp',[107,97,108,108,101],true},{'XSeqImp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','XExpImp',lists:flatten(Bytes53)),
-
-
-
- ?line {ok,Bytes61} =
- asn1_wrapper:encode('SeqOfExternal','XNTExp',[#'XSeqExp'{bool = true, os = "kalle"},
- #'XSeqExp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSeqExp',[107,97,108,108,101],true},{'XSeqExp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','XNTExp',lists:flatten(Bytes61)),
-
- ?line {ok,Bytes62} =
- asn1_wrapper:encode('SeqOfExternal','XImpExp',[#'XSeqExp'{bool = true, os = "kalle"},
- #'XSeqExp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSeqExp',[107,97,108,108,101],true},{'XSeqExp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','XImpExp',lists:flatten(Bytes62)),
-
- ?line {ok,Bytes63} =
- asn1_wrapper:encode('SeqOfExternal','XExpExp',[#'XSeqExp'{bool = true, os = "kalle"},
- #'XSeqExp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSeqExp',[107,97,108,108,101],true},{'XSeqExp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SeqOfExternal','XExpExp',lists:flatten(Bytes63)),
-
-
-
-
+ roundtrip('NTNT',
+ [#'NT'{os="kalle",bool=true},#'NT'{os="kalle",bool=true}]),
+ roundtrip('ImpNT',
+ [#'NT'{os="kalle",bool=true},#'NT'{os="kalle",bool=true}]),
+ roundtrip('ExpNT',
+ [#'NT'{os="kalle",bool=true},#'NT'{os="kalle",bool=true}]),
+ roundtrip('NTImp',
+ [#'Imp'{os="kalle",bool=true},#'Imp'{os="kalle",bool=true}]),
+ roundtrip('ImpImp',
+ [#'Imp'{os="kalle",bool=true},#'Imp'{os="kalle",bool=true}]),
+ roundtrip('ExpImp',
+ [#'Imp'{os="kalle",bool=true},#'Imp'{os="kalle",bool=true}]),
+ roundtrip('NTExp',
+ [#'Exp'{os="kalle",bool=true},#'Exp'{os="kalle",bool=true}]),
+ roundtrip('ImpExp',
+ [#'Exp'{os="kalle",bool=true},#'Exp'{os="kalle",bool=true}]),
+ roundtrip('ExpExp',
+ [#'Exp'{os="kalle",bool=true},#'Exp'{os="kalle",bool=true}]),
+ roundtrip('XNTNT',
+ [#'XSeqNT'{os="kalle",bool=true},
+ #'XSeqNT'{os="kalle",bool=true}]),
+ roundtrip('XImpNT',
+ [#'XSeqNT'{os="kalle",bool=true},
+ #'XSeqNT'{os="kalle",bool=true}]),
+ roundtrip('XExpNT',
+ [#'XSeqNT'{os="kalle",bool=true},
+ #'XSeqNT'{os="kalle",bool=true}]),
+ roundtrip('XNTImp',
+ [#'XSeqImp'{os="kalle",bool=true},
+ #'XSeqImp'{os="kalle",bool=true}]),
+ roundtrip('XImpImp',
+ [#'XSeqImp'{os="kalle",bool=true},
+ #'XSeqImp'{os="kalle",bool=true}]),
+ roundtrip('XExpImp',
+ [#'XSeqImp'{os="kalle",bool=true},
+ #'XSeqImp'{os="kalle",bool=true}]),
+ roundtrip('XNTExp',
+ [#'XSeqExp'{os="kalle",bool=true},
+ #'XSeqExp'{os="kalle",bool=true}]),
+ roundtrip('XImpExp',
+ [#'XSeqExp'{os="kalle",bool=true},
+ #'XSeqExp'{os="kalle",bool=true}]),
+ roundtrip('XExpExp',
+ [#'XSeqExp'{os="kalle",bool=true},
+ #'XSeqExp'{os="kalle",bool=true}]),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SeqOfExternal', T, V).
diff --git a/lib/asn1/test/testSeqOfIndefinite.erl b/lib/asn1/test/testSeqOfIndefinite.erl
index 01ef36e0b4..b771405d84 100644
--- a/lib/asn1/test/testSeqOfIndefinite.erl
+++ b/lib/asn1/test/testSeqOfIndefinite.erl
@@ -33,60 +33,53 @@ main() ->
?line ok = test('InsertSubscriberDataArg'). % OTP-4232
test(isd)->
- EncPdu = [48,128,129,7,145,148,113,50,1,0,241,131,1,0,176,128,5,0,161,128,48,22,2,1,1,144,2,241,33,145,4,0,1,2,3,146,3,36,131,16,148,2,1,42,48,35,2,1,2,144,2,241,33,145,4,255,255,255,255,146,3,37,147,18,147,0,148,13,7,67,79,77,80,65,78,89,4,67,79,77,53,48,28,2,1,3,144,2,241,33,146,3,26,98,31,148,14,9,67,79,77,80,65,78,89,49,50,3,67,79,77,0,0,0,0,152,1,2,0,0],
-
- ?line {ok,_} = asn1_wrapper:decode('Mvrasn-11-4',
- 'InsertSubscriberDataArg',
- EncPdu),
+ EncPdu = <<48,128,129,7,145,148,113,50,1,0,241,131,1,0,176,128,5,0,
+ 161,128,48,22,2,1,1,144,2,241,33,145,4,0,1,2,3,146,3,36,
+ 131,16,148,2,1,42,48,35,2,1,2,144,2,241,33,145,4,255,255,
+ 255,255,146,3,37,147,18,147,0,148,13,7,67,79,77,80,65,78,
+ 89,4,67,79,77,53,48,28,2,1,3,144,2,241,33,146,3,26,98,31,
+ 148,14,9,67,79,77,80,65,78,89,49,50,3,67,79,77,0,0,0,0,
+ 152,1,2,0,0>>,
+ {ok,_} = 'Mvrasn-11-4':decode('InsertSubscriberDataArg', EncPdu),
ok;
%
% Problems with indefinite length encoding !!!
%
test(isd2)->
- EncPdu = [48, 128, 128, 8, 98, 2, 50, 1, 0, 0, 0, 241, 176, 128, 161, 128, 48, 128, 2, 1, 1, 144, 2, 241, 33, 145, 4, 255, 23, 12, 1, 146, 3, 9, 17, 1, 147, 0, 148, 13, 7, 67, 79, 77, 80, 65, 78, 89, 4, 67, 79, 77, 53, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
-
- ?line {ok,_DecPdu} = asn1_wrapper:decode('Mvrasn-11-4',
- 'InsertSubscriberDataArg',
- EncPdu),
-
+ EncPdu = <<48,128,128,8,98,2,50,1,0,0,0,241,176,128,161,128,48,128,2,1,1,144,
+ 2,241,33,145,4,255,23,12,1,146,3,9,17,1,147,0,148,13,7,67,79,77,80,
+ 65,78,89,4,67,79,77,53,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0>>,
+ {ok,_DecPdu} = 'Mvrasn-11-4':decode('InsertSubscriberDataArg', EncPdu),
ok;
%
% Is doing fine, although there is indefinite encoding used... !!!
%
test(dsd)->
- EncPdu = [48, 128, 128, 8, 98, 2, 50, 1, 0, 0, 0, 241, 170, 2, 5, 0, 0, 0, 0, 0],
-
- ?line {ok,_DecPdu} = asn1_wrapper:decode('Mvrasn-11-4',
- 'DeleteSubscriberDataArg',
- EncPdu),
-
+ EncPdu = <<48,128,128,8,98,2,50,1,0,0,0,241,170,2,5,0,0,0,0,0>>,
+ {ok,_DecPdu} = 'Mvrasn-11-4':decode('DeleteSubscriberDataArg', EncPdu),
ok;
%
% Is doing fine !!!
%
test(ul_res)->
- EncPdu = [48, 9, 4, 7, 145, 148, 113, 66, 16, 17, 241],
-
- ?line {ok,_DecPdu} = asn1_wrapper:decode('Mvrasn-11-4',
- 'UpdateGprsLocationRes',
- EncPdu),
-
+ EncPdu = <<48,9,4,7,145,148,113,66,16,17,241>>,
+ {ok,_DecPdu} = 'Mvrasn-11-4':decode('UpdateGprsLocationRes', EncPdu),
ok;
test(prim) ->
- ?line {ok,Bytes} = asn1_wrapper:encode('SeqOf','SeqOfInt',[10,20,30]),
- ?line [Tag,_Len|Ints] = lists:flatten(Bytes),
- ?line {ok,[10,20,30]} =
- asn1_wrapper:decode('SeqOf','SeqOfInt',[Tag,128|Ints] ++ [0,0]),
+ Bytes = asn1_test_lib:roundtrip_enc('SeqOf', 'SeqOfInt', [10,20,30]),
+ <<Tag,_Len,Ints/binary>> = Bytes,
+ {ok,[10,20,30]} =
+ 'SeqOf':decode('SeqOfInt', <<Tag,128,Ints/binary,0,0>>),
ok;
test(seqofseq) ->
- {ok,_V} = asn1_wrapper:decode('Mvrasn-DataTypes-1',
- 'SentParameters',
- [48,
+ {ok,_V} = 'Mvrasn-DataTypes-1':decode(
+ 'SentParameters',
+ [48,
129,
190,
161,
@@ -281,17 +274,16 @@ test(seqofseq) ->
0]),
ok;
test('InsertSubscriberDataArg') ->
- {ok,_V} =
- asn1_wrapper:decode('Mvrasn-11-4','InsertSubscriberDataArg',
- [16#30,16#80,16#81,16#07,16#91,16#94,
- 16#71,16#92,16#00,16#35,16#80,16#83,
- 16#01,16#00,16#A6,16#06,16#04,16#01,
- 16#21,16#04,16#01,16#22,16#B0,16#80,
- 16#05,16#00,16#A1,16#80,16#30,16#1A,
- 16#02,16#01,16#01,16#90,16#02,16#F1,
- 16#21,16#92,16#03,16#0D,16#92,16#1F,
- 16#94,16#0C,16#03,16#53,16#49,16#4D,
- 16#03,16#47,16#53,16#4E,16#03,16#4C,
- 16#4B,16#50,16#00,16#00,16#00,16#00,
- 16#98,16#01,16#00,16#00,16#00]),
+ EncPdu = <<16#30,16#80,16#81,16#07,16#91,16#94,
+ 16#71,16#92,16#00,16#35,16#80,16#83,
+ 16#01,16#00,16#A6,16#06,16#04,16#01,
+ 16#21,16#04,16#01,16#22,16#B0,16#80,
+ 16#05,16#00,16#A1,16#80,16#30,16#1A,
+ 16#02,16#01,16#01,16#90,16#02,16#F1,
+ 16#21,16#92,16#03,16#0D,16#92,16#1F,
+ 16#94,16#0C,16#03,16#53,16#49,16#4D,
+ 16#03,16#47,16#53,16#4E,16#03,16#4C,
+ 16#4B,16#50,16#00,16#00,16#00,16#00,
+ 16#98,16#01,16#00,16#00,16#00>>,
+ {ok,_V} = 'Mvrasn-11-4':decode('InsertSubscriberDataArg', EncPdu),
ok.
diff --git a/lib/asn1/test/testSeqOfTag.erl b/lib/asn1/test/testSeqOfTag.erl
index 2359df0c59..38c1dcb90f 100644
--- a/lib/asn1/test/testSeqOfTag.erl
+++ b/lib/asn1/test/testSeqOfTag.erl
@@ -44,145 +44,48 @@
-record('Exp',{os, bool}).
main(_Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SeqOfTag','SeqTagNt',
- #'SeqTagNt'{nt = [#'NT'{bool = true, os = "kalle"},
- #'NT'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagNt',
- [{'NT',[107,97,108,108,101],true},{'NT',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagNt',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SeqOfTag','SeqTagNtI',
- #'SeqTagNtI'{imp = [#'Imp'{bool = true, os = "kalle"},
- #'Imp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagNtI',
- [{'Imp',[107,97,108,108,101],true},{'Imp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagNtI',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SeqOfTag','SeqTagNtE',
- #'SeqTagNtE'{exp = [#'Exp'{bool = true, os = "kalle"},
- #'Exp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagNtE',
- [{'Exp',[107,97,108,108,101],true},{'Exp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagNtE',lists:flatten(Bytes13)),
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SeqOfTag','SeqTagI',
- #'SeqTagI'{nt = [#'NT'{bool = true, os = "kalle"},
- #'NT'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagI',
- [{'NT',[107,97,108,108,101],true},{'NT',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagI',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SeqOfTag','SeqTagII',
- #'SeqTagII'{imp = [#'Imp'{bool = true, os = "kalle"},
- #'Imp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagII',
- [{'Imp',[107,97,108,108,101],true},{'Imp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagII',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('SeqOfTag','SeqTagIE',
- #'SeqTagIE'{exp = [#'Exp'{bool = true, os = "kalle"},
- #'Exp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagIE',
- [{'Exp',[107,97,108,108,101],true},{'Exp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagIE',lists:flatten(Bytes23)),
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SeqOfTag','SeqTagE',
- #'SeqTagE'{nt = [#'NT'{bool = true, os = "kalle"},
- #'NT'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagE',
- [{'NT',[107,97,108,108,101],true},{'NT',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagE',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} =
- asn1_wrapper:encode('SeqOfTag','SeqTagEI',
- #'SeqTagEI'{imp = [#'Imp'{bool = true, os = "kalle"},
- #'Imp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagEI',
- [{'Imp',[107,97,108,108,101],true},{'Imp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagEI',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes33} =
- asn1_wrapper:encode('SeqOfTag','SeqTagEE',
- #'SeqTagEE'{exp = [#'Exp'{bool = true, os = "kalle"},
- #'Exp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagEE',
- [{'Exp',[107,97,108,108,101],true},{'Exp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagEE',lists:flatten(Bytes33)),
-
-
-
-
+ roundtrip('SeqTagNt', #'SeqTagNt'{nt=[#'NT'{os="kalle",bool=true},
+ #'NT'{os="kalle",bool=true}]}),
+ roundtrip('SeqTagNtI', #'SeqTagNtI'{imp=[#'Imp'{os="kalle",bool=true},
+ #'Imp'{os="kalle",bool=true}]}),
+ roundtrip('SeqTagNtE', #'SeqTagNtE'{exp=[#'Exp'{os="kalle",bool=true},
+ #'Exp'{os="kalle",bool=true}]}),
+ roundtrip('SeqTagI', #'SeqTagI'{nt=[#'NT'{os="kalle",bool=true},
+ #'NT'{os="kalle",bool=true}]}),
+ roundtrip('SeqTagII', #'SeqTagII'{imp=[#'Imp'{os="kalle",bool=true},
+ #'Imp'{os="kalle",bool=true}]}),
+ roundtrip('SeqTagIE', #'SeqTagIE'{exp=[#'Exp'{os="kalle",bool=true},
+ #'Exp'{os="kalle",bool=true}]}),
+ roundtrip('SeqTagE', #'SeqTagE'{nt=[#'NT'{os="kalle",bool=true},
+ #'NT'{os="kalle",bool=true}]}),
+ roundtrip('SeqTagEI', #'SeqTagEI'{imp=[#'Imp'{os="kalle",bool=true},
+ #'Imp'{os="kalle",bool=true}]}),
+ roundtrip('SeqTagEE', #'SeqTagEE'{exp=[#'Exp'{os="kalle",bool=true},
+ #'Exp'{os="kalle",bool=true}]}),
+ roundtrip('SeqTagXNt',
+ #'SeqTagXNt'{xnt=[#'XSeqNT'{os="kalle",bool=true},
+ #'XSeqNT'{os="kalle",bool=true}]}),
+ roundtrip('SeqTagXI',
+ #'SeqTagXI'{ximp=[#'XSeqImp'{os="kalle",bool=true},
+ #'XSeqImp'{os="kalle",bool=true}]}),
+ roundtrip('SeqTagXE',
+ #'SeqTagXE'{xexp=[#'XSeqExp'{os="kalle",bool=true},
+ #'XSeqExp'{os="kalle",bool=true}]}),
+ roundtrip('SeqTagImpX',
+ #'SeqTagImpX'{xnt=[#'XSeqNT'{os="kalle",bool=true},
+ #'XSeqNT'{os="kalle",bool=true}],
+ ximp=[#'XSeqImp'{os="kalle",bool=true},
+ #'XSeqImp'{os="kalle",bool=true}],
+ xexp=[#'XSeqExp'{os="kalle",bool=true},
+ #'XSeqExp'{os="kalle",bool=true}]}),
+ roundtrip('SeqTagExpX',
+ #'SeqTagExpX'{xnt=[#'XSeqNT'{os="kalle",bool=true},
+ #'XSeqNT'{os="kalle",bool=true}],
+ ximp=[#'XSeqImp'{os="kalle",bool=true},
+ #'XSeqImp'{os="kalle",bool=true}],
+ xexp=[#'XSeqExp'{os="kalle",bool=true},
+ #'XSeqExp'{os="kalle",bool=true}]}),
+ ok.
-
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SeqOfTag','SeqTagXNt',
- #'SeqTagXNt'{xnt = [#'XSeqNT'{bool = true, os = "kalle"},
- #'XSeqNT'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagXNt',
- [{'XSeqNT',[107,97,108,108,101],true},{'XSeqNT',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagXNt',lists:flatten(Bytes41)),
-
- ?line {ok,Bytes42} =
- asn1_wrapper:encode('SeqOfTag','SeqTagXI',
- #'SeqTagXI'{ximp = [#'XSeqImp'{bool = true, os = "kalle"},
- #'XSeqImp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagXI',
- [{'XSeqImp',[107,97,108,108,101],true},{'XSeqImp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagXI',lists:flatten(Bytes42)),
-
- ?line {ok,Bytes43} =
- asn1_wrapper:encode('SeqOfTag','SeqTagXE',
- #'SeqTagXE'{xexp = [#'XSeqExp'{bool = true, os = "kalle"},
- #'XSeqExp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagXE',
- [{'XSeqExp',[107,97,108,108,101],true},{'XSeqExp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagXE',lists:flatten(Bytes43)),
-
-
-
-
-
- ?line {ok,Bytes51} =
- asn1_wrapper:encode('SeqOfTag','SeqTagImpX',
- #'SeqTagImpX'{xnt = [#'XSeqNT'{bool = true, os = "kalle"},
- #'XSeqNT'{bool = true, os = "kalle"}],
- ximp = [#'XSeqImp'{bool = true, os = "kalle"},
- #'XSeqImp'{bool = true, os = "kalle"}],
- xexp = [#'XSeqExp'{bool = true, os = "kalle"},
- #'XSeqExp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagImpX',
- [{'XSeqNT',[107,97,108,108,101],true},{'XSeqNT',[107,97,108,108,101],true}],
- [{'XSeqImp',[107,97,108,108,101],true},{'XSeqImp',[107,97,108,108,101],true}],
- [{'XSeqExp',[107,97,108,108,101],true},{'XSeqExp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagImpX',lists:flatten(Bytes51)),
-
-
-
- ?line {ok,Bytes52} =
- asn1_wrapper:encode('SeqOfTag','SeqTagExpX',
- #'SeqTagExpX'{xnt = [#'XSeqNT'{bool = true, os = "kalle"},
- #'XSeqNT'{bool = true, os = "kalle"}],
- ximp = [#'XSeqImp'{bool = true, os = "kalle"},
- #'XSeqImp'{bool = true, os = "kalle"}],
- xexp = [#'XSeqExp'{bool = true, os = "kalle"},
- #'XSeqExp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SeqTagExpX',
- [{'XSeqNT',[107,97,108,108,101],true},{'XSeqNT',[107,97,108,108,101],true}],
- [{'XSeqImp',[107,97,108,108,101],true},{'XSeqImp',[107,97,108,108,101],true}],
- [{'XSeqExp',[107,97,108,108,101],true},{'XSeqExp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SeqOfTag','SeqTagExpX',lists:flatten(Bytes52)),
-
-ok.
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SeqOfTag', T, V).
diff --git a/lib/asn1/test/testSeqOptional.erl b/lib/asn1/test/testSeqOptional.erl
index 8013f3c685..c9478105a4 100644
--- a/lib/asn1/test/testSeqOptional.erl
+++ b/lib/asn1/test/testSeqOptional.erl
@@ -37,159 +37,48 @@
-record('SeqChoOpt',{int, cho = asn1_NOVALUE}).
main(_Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SeqOptional','SeqOpt1',#'SeqOpt1'{bool1 = true,
- int1 = 15,
- seq1 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqOpt1',true,15,{'SeqIn',true,66}}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt1',lists:flatten(Bytes11)),
-
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('SeqOptional','SeqOpt1',#'SeqOpt1'{int1 = 15}),
- ?line {ok,{'SeqOpt1',asn1_NOVALUE,15,asn1_NOVALUE}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt1',lists:flatten(Bytes12)),
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SeqOptional','SeqOpt2',#'SeqOpt2'{bool2 = true,
- int2 = 15,
- seq2 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqOpt2',{'SeqIn',true,66},true,15}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt2',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('SeqOptional','SeqOpt2',#'SeqOpt2'{int2 = 15,
- bool2 = true}),
- ?line {ok,{'SeqOpt2',asn1_NOVALUE,true,15}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt2',lists:flatten(Bytes22)),
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SeqOptional','SeqOpt3',#'SeqOpt3'{bool3 = true,
- int3 = 15,
- seq3 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqOpt3',true,{'SeqIn',true,66},15}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt3',lists:flatten(Bytes31)),
-
-
- ?line {ok,Bytes32} = asn1_wrapper:encode('SeqOptional','SeqOpt3',#'SeqOpt3'{int3 = 15}),
- ?line {ok,{'SeqOpt3',asn1_NOVALUE,asn1_NOVALUE,15}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt3',lists:flatten(Bytes32)),
-
-
-
-
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SeqOptional','SeqOpt1Imp',#'SeqOpt1Imp'{bool1 = true,
- int1 = 15,
- seq1 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqOpt1Imp',true,15,{'SeqIn',true,66}}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt1Imp',lists:flatten(Bytes41)),
-
-
- ?line {ok,Bytes42} = asn1_wrapper:encode('SeqOptional','SeqOpt1Imp',#'SeqOpt1Imp'{int1 = 15}),
- ?line {ok,{'SeqOpt1Imp',asn1_NOVALUE,15,asn1_NOVALUE}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt1Imp',lists:flatten(Bytes42)),
-
-
- ?line {ok,Bytes51} =
- asn1_wrapper:encode('SeqOptional','SeqOpt2Imp',#'SeqOpt2Imp'{bool2 = true,
- int2 = 15,
- seq2 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqOpt2Imp',{'SeqIn',true,66},true,15}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt2Imp',lists:flatten(Bytes51)),
-
-
- ?line {ok,Bytes52} = asn1_wrapper:encode('SeqOptional','SeqOpt2Imp',#'SeqOpt2Imp'{int2 = 15,
- bool2 = true}),
- ?line {ok,{'SeqOpt2Imp',asn1_NOVALUE,true,15}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt2Imp',lists:flatten(Bytes52)),
-
-
-
- ?line {ok,Bytes61} =
- asn1_wrapper:encode('SeqOptional','SeqOpt3Imp',#'SeqOpt3Imp'{bool3 = true,
- int3 = 15,
- seq3 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqOpt3Imp',true,{'SeqIn',true,66},15}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt3Imp',lists:flatten(Bytes61)),
-
-
- ?line {ok,Bytes62} = asn1_wrapper:encode('SeqOptional','SeqOpt3Imp',#'SeqOpt3Imp'{int3 = 15}),
- ?line {ok,{'SeqOpt3Imp',asn1_NOVALUE,asn1_NOVALUE,15}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt3Imp',lists:flatten(Bytes62)),
-
-
-
-
-
-
- ?line {ok,Bytes71} =
- asn1_wrapper:encode('SeqOptional','SeqOpt1Exp',#'SeqOpt1Exp'{bool1 = true,
- int1 = 15,
- seq1 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqOpt1Exp',true,15,{'SeqIn',true,66}}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt1Exp',lists:flatten(Bytes71)),
-
-
- ?line {ok,Bytes72} = asn1_wrapper:encode('SeqOptional','SeqOpt1Exp',#'SeqOpt1Exp'{int1 = 15}),
- ?line {ok,{'SeqOpt1Exp',asn1_NOVALUE,15,asn1_NOVALUE}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt1Exp',lists:flatten(Bytes72)),
-
-
- ?line {ok,Bytes81} =
- asn1_wrapper:encode('SeqOptional','SeqOpt2Exp',#'SeqOpt2Exp'{bool2 = true,
- int2 = 15,
- seq2 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqOpt2Exp',{'SeqIn',true,66},true,15}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt2Exp',lists:flatten(Bytes81)),
-
-
- ?line {ok,Bytes82} = asn1_wrapper:encode('SeqOptional','SeqOpt2Exp',#'SeqOpt2Exp'{int2 = 15,
- bool2 = true}),
- ?line {ok,{'SeqOpt2Exp',asn1_NOVALUE,true,15}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt2Exp',lists:flatten(Bytes82)),
-
-
-
- ?line {ok,Bytes91} =
- asn1_wrapper:encode('SeqOptional','SeqOpt3Exp',#'SeqOpt3Exp'{bool3 = true,
- int3 = 15,
- seq3 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqOpt3Exp',true,{'SeqIn',true,66},15}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt3Exp',lists:flatten(Bytes91)),
-
-
- ?line {ok,Bytes92} = asn1_wrapper:encode('SeqOptional','SeqOpt3Exp',#'SeqOpt3Exp'{int3 = 15}),
- ?line {ok,{'SeqOpt3Exp',asn1_NOVALUE,asn1_NOVALUE,15}} =
- asn1_wrapper:decode('SeqOptional','SeqOpt3Exp',lists:flatten(Bytes92)),
-
-
-
- ?line {ok,Bytes101} =
- asn1_wrapper:encode('SeqOptional','SeqChoOpt',#'SeqChoOpt'{int = 15,
- cho = {boolC,true}}),
- ?line {ok,{'SeqChoOpt',15,{boolC,true}}} =
- asn1_wrapper:decode('SeqOptional','SeqChoOpt',lists:flatten(Bytes101)),
-
-
- ?line {ok,Bytes102} = asn1_wrapper:encode('SeqOptional','SeqChoOpt',#'SeqChoOpt'{int = 15}),
- ?line {ok,{'SeqChoOpt',15,asn1_NOVALUE}} =
- asn1_wrapper:decode('SeqOptional','SeqChoOpt',lists:flatten(Bytes102)),
-
-
-
-
+ roundtrip('SeqOpt1', #'SeqOpt1'{bool1=true,int1=15,
+ seq1=#'SeqIn'{boolIn=true,intIn=66}}),
+ roundtrip('SeqOpt1', #'SeqOpt1'{bool1=asn1_NOVALUE,
+ int1=15,seq1=asn1_NOVALUE}),
+ roundtrip('SeqOpt2', #'SeqOpt2'{seq2=#'SeqIn'{boolIn=true,intIn=66},
+ bool2=true,int2=15}),
+ roundtrip('SeqOpt2', #'SeqOpt2'{seq2=asn1_NOVALUE,bool2=true,int2=15}),
+ roundtrip('SeqOpt3', #'SeqOpt3'{bool3=true,
+ seq3=#'SeqIn'{boolIn=true,
+ intIn=66},int3=15}),
+ roundtrip('SeqOpt3', #'SeqOpt3'{bool3=asn1_NOVALUE,
+ seq3=asn1_NOVALUE,int3=15}),
+ roundtrip('SeqOpt1Imp', #'SeqOpt1Imp'{bool1=true,int1=15,
+ seq1=#'SeqIn'{boolIn=true,intIn=66}}),
+ roundtrip('SeqOpt1Imp', #'SeqOpt1Imp'{bool1=asn1_NOVALUE,
+ int1=15,seq1=asn1_NOVALUE}),
+ roundtrip('SeqOpt2Imp', #'SeqOpt2Imp'{seq2=#'SeqIn'{boolIn=true,intIn=66},
+ bool2=true,int2=15}),
+ roundtrip('SeqOpt2Imp', #'SeqOpt2Imp'{seq2=asn1_NOVALUE,
+ bool2=true,int2=15}),
+ roundtrip('SeqOpt3Imp', #'SeqOpt3Imp'{bool3=true,
+ seq3=#'SeqIn'{boolIn=true,intIn=66},
+ int3=15}),
+ roundtrip('SeqOpt3Imp', #'SeqOpt3Imp'{bool3=asn1_NOVALUE,
+ seq3=asn1_NOVALUE,int3=15}),
+ roundtrip('SeqOpt1Exp', #'SeqOpt1Exp'{bool1=true,int1=15,
+ seq1=#'SeqIn'{boolIn=true,
+ intIn=66}}),
+ roundtrip('SeqOpt1Exp', #'SeqOpt1Exp'{bool1=asn1_NOVALUE,
+ int1=15,seq1=asn1_NOVALUE}),
+ roundtrip('SeqOpt2Exp', #'SeqOpt2Exp'{seq2=#'SeqIn'{boolIn=true,intIn=66},
+ bool2=true,int2=15}),
+ roundtrip('SeqOpt2Exp', #'SeqOpt2Exp'{seq2=asn1_NOVALUE,
+ bool2=true,int2=15}),
+ roundtrip('SeqOpt3Exp', #'SeqOpt3Exp'{bool3=true,
+ seq3=#'SeqIn'{boolIn=true,intIn=66},
+ int3=15}),
+ roundtrip('SeqOpt3Exp', #'SeqOpt3Exp'{bool3=asn1_NOVALUE,
+ seq3=asn1_NOVALUE,int3=15}),
+ roundtrip('SeqChoOpt', #'SeqChoOpt'{int=15,cho={boolC,true}}),
+ roundtrip('SeqChoOpt', #'SeqChoOpt'{int=15,cho=asn1_NOVALUE}),
ok.
+
+roundtrip(Type, Value) ->
+ asn1_test_lib:roundtrip('SeqOptional', Type, Value).
diff --git a/lib/asn1/test/testSeqPrim.erl b/lib/asn1/test/testSeqPrim.erl
index c2451a7cd1..eb21d50a37 100644
--- a/lib/asn1/test/testSeqPrim.erl
+++ b/lib/asn1/test/testSeqPrim.erl
@@ -27,58 +27,15 @@
-record('Empty',{}).
main(_Rules) ->
-
-
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SeqPrim','Seq',#'Seq'{bool = true,
- boolCon = true,
- boolPri = true,
- boolApp = true,
- boolExpCon = true,
- boolExpPri = true,
- boolExpApp = true}),
- ?line {ok,{'Seq',true,true,true,true,true,true,true}} =
- asn1_wrapper:decode('SeqPrim','Seq',lists:flatten(Bytes11)),
-
-
-
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SeqPrim','Seq',#'Seq'{bool = false,
- boolCon = false,
- boolPri = false,
- boolApp = false,
- boolExpCon = false,
- boolExpPri = false,
- boolExpApp = false}),
- ?line {ok,{'Seq',false,false,false,false,false,false,false}} =
- asn1_wrapper:decode('SeqPrim','Seq',lists:flatten(Bytes12)),
-
-
-
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SeqPrim','Seq',#'Seq'{bool = false,
- boolCon = true,
- boolPri = false,
- boolApp = true,
- boolExpCon = false,
- boolExpPri = true,
- boolExpApp = false}),
- ?line {ok,{'Seq',false,true,false,true,false,true,false}} =
- asn1_wrapper:decode('SeqPrim','Seq',lists:flatten(Bytes13)),
-
-
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SeqPrim','Empty',#'Empty'{}),
- ?line {ok,{'Empty'}} =
- asn1_wrapper:decode('SeqPrim','Empty',lists:flatten(Bytes21)),
-
-
-
+ roundtrip('Seq', #'Seq'{bool=true,boolCon=true,boolPri=true,boolApp=true,
+ boolExpCon=true,boolExpPri=true,boolExpApp=true}),
+ roundtrip('Seq', #'Seq'{bool=false,boolCon=false,boolPri=false,
+ boolApp=false,boolExpCon=false,
+ boolExpPri=false,boolExpApp=false}),
+ roundtrip('Seq', #'Seq'{bool=false,boolCon=true,boolPri=false,boolApp=true,
+ boolExpCon=false,boolExpPri=true,boolExpApp=false}),
+ roundtrip('Empty', #'Empty'{}),
ok.
+roundtrip(Type, Value) ->
+ asn1_test_lib:roundtrip('SeqPrim', Type, Value).
diff --git a/lib/asn1/test/testSeqSetDefaultVal.erl b/lib/asn1/test/testSeqSetDefaultVal.erl
index bd6c9428e2..044099199f 100644
--- a/lib/asn1/test/testSeqSetDefaultVal.erl
+++ b/lib/asn1/test/testSeqSetDefaultVal.erl
@@ -18,10 +18,9 @@
%%
%%
-module(testSeqSetDefaultVal).
+-export([main/2]).
-include("External.hrl").
--export([main/1]).
-
-include_lib("test_server/include/test_server.hrl").
-record('SeqInts',{a = asn1_DEFAULT,
@@ -35,7 +34,8 @@
-record('SeqBS',{a = asn1_DEFAULT,
b = asn1_DEFAULT,
c = asn1_DEFAULT,
- d = asn1_DEFAULT}).
+ d = asn1_DEFAULT,
+ e = asn1_DEFAULT}).
-record('SetBS',{a = asn1_DEFAULT,
b = asn1_DEFAULT,
c = asn1_DEFAULT,
@@ -94,243 +94,368 @@
-record('S4_b',{ba = asn1_DEFAULT,
bb = asn1_DEFAULT}).
-main(_Rules) ->
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','SeqInts',#'SeqInts'{}),
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','SeqInts',#'SeqInts'{a=1,b=-1,c=three,
- d=1}),
- ?line {ok,{'SeqInts',1,-1,3,1}} =
- asn1_wrapper:decode('Default','SeqInts',[48,0]),
-
- ?line {ok,[49,0]} =
- asn1_wrapper:encode('Default','SetInts',#'SetInts'{}),
- ?line {ok,[49,0]} =
- asn1_wrapper:encode('Default','SetInts',#'SetInts'{a=1,b=-1,c=three,
- d=1}),
- ?line {ok,{'SetInts',1,-1,3,1}} =
- asn1_wrapper:decode('Default','SetInts',[49,0]),
-
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','SeqBS',
- #'SeqBS'{a=2#1010110,
- b=16#A8A,
- c=[second],
- d=[1,0,0,1]}),
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','SeqBS',
- #'SeqBS'{a=[1,0,1,0,1,1,0],
- b=[1,0,1,0,1,0,0,0,1,0,1,0],
- c={5,<<64>>},
- d=9}),
-
- ?line {ok,[48,3,131,1,0]} =
- asn1_wrapper:encode('Default','SeqBS',
- #'SeqBS'{a=[1,0,1,0,1,1,0],
- b=[1,0,1,0,1,0,0,0,1,0,1,0],
- c={5,<<64>>},
- d=0}),
-
- {ok,{'SeqBS',[1,0,1,0,1,1,0],2698,[second],<<>>}} =
- asn1_wrapper:decode('Default','SeqBS',[48,3,131,1,0]),
-
- ?line {ok,{'SeqBS',[1,0,1,0,1,1,0],2698,[second],[1,0,0,1]}} =
- asn1_wrapper:decode('Default','SeqBS',[48,0]),
-
- ?line {ok,[49,0]} =
- asn1_wrapper:encode('Default','SetBS',
- #'SetBS'{a=2#1010110,
- b=16#A8A,
- c=[second],
- d=[1,0,0,1]}),
-
- ?line {ok,[49,0]} =
- asn1_wrapper:encode('Default','SetBS',
- #'SetBS'{a=[1,0,1,0,1,1,0],
- b=[1,0,1,0,1,0,0,0,1,0,1,0],
- c={5,<<64>>},
- d=9}),
-
- ?line {ok,[49,3,131,1,0]} =
- asn1_wrapper:encode('Default','SetBS',
- #'SetBS'{a=[1,0,1,0,1,1,0],
- b=[1,0,1,0,1,0,0,0,1,0,1,0],
- c={5,<<64>>},
- d=0}),
-
- {ok,{'SetBS',[1,0,1,0,1,1,0],2698,[second],<<>>}} =
- asn1_wrapper:decode('Default','SetBS',[49,3,131,1,0]),
-
- ?line {ok,{'SetBS',[1,0,1,0,1,1,0],2698,[second],[1,0,0,1]}} =
- asn1_wrapper:decode('Default','SetBS',[49,0]),
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','SeqOS',
- #'SeqOS'{a=[172],
- b=[16#A8,16#A0],
- c='NULL'}),
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','SeqOS',
- #'SeqOS'{a=2#10101100,
- b=16#A8A0,
- c='NULL'}),
-
- ?line {ok,{'SeqOS',[172],[16#A8,16#A0],'NULL'}} =
- asn1_wrapper:decode('Default','SeqOS',[48,0]),
-
- ?line {ok,[49,0]} =
- asn1_wrapper:encode('Default','SetOS',
- #'SetOS'{a=[172],
- b=[16#A8,16#A0],
- c='NULL'}),
-
- ?line {ok,[49,0]} =
- asn1_wrapper:encode('Default','SetOS',
- #'SetOS'{a=2#10101100,
- b=16#A8A0,
- c='NULL'}),
-
- ?line {ok,{'SetOS',[172],[16#A8,16#A0],'NULL'}} =
- asn1_wrapper:decode('Default','SetOS',[49,0]),
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','SeqOI',
- #'SeqOI'{a={1,2,14,15},
- b={iso,'member-body',250,3,4},
- c={iso,standard,8571,2,250,4}}),
-
- ?line {ok,{'SeqOI',{1,2,14,15},{1,2,250,3,4},{1,0,8571,2,250,4}}} =
- asn1_wrapper:decode('Default','SeqOI',[48,0]),
-
- ?line {ok,[49,0]} =
- asn1_wrapper:encode('Default','SetOI',
- #'SetOI'{a={1,2,14,15},
- b={iso,'member-body',250,3,4},
- c={iso,standard,8571,2,250,4}}),
-
- ?line {ok,{'SetOI',{1,2,14,15},{1,2,250,3,4},{1,0,8571,2,250,4}}} =
- asn1_wrapper:decode('Default','SetOI',[49,0]),
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','SeqEnum',#'SeqEnum'{a=b4,b=b2}),
-
- ?line {ok,{'SeqEnum',b4,b2}} =
- asn1_wrapper:decode('Default','SeqEnum',[48,0]),
-
- ?line {ok,[49,0]} =
- asn1_wrapper:encode('Default','SetEnum',#'SetEnum'{a=b4,b=b2}),
-
- ?line {ok,{'SetEnum',b4,b2}} =
- asn1_wrapper:decode('Default','SetEnum',[49,0]),
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','SeqIntBool',
- #'SeqIntBool'{a=#'SeqIntBool_a'{aa=12,ab=13},
- b=#'S2'{a=14,b=true},
- c=#'S2'{a=15,b=false}}),
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','SeqIntBool',
- #'SeqIntBool'{}),
-
- ?line {ok,{'SeqIntBool',{'SeqIntBool_a',12,13},
- {'S2',14,true},{'S2',15,false}}} =
- asn1_wrapper:decode('Default','SeqIntBool',[48,0]),
-
- ?line {ok,[49,0]} =
- asn1_wrapper:encode('Default','SetIntBool',
- #'SetIntBool'{a=#'SetIntBool_a'{aa=12,ab=13},
- b=#'S2'{a=14,b=true},
- c=#'S2'{a=15,b=false}}),
-
- ?line {ok,[49,0]} =
- asn1_wrapper:encode('Default','SetIntBool',
- #'SetIntBool'{}),
-
- ?line {ok,{'SetIntBool',{'SetIntBool_a',12,13},
- {'S2',14,true},{'S2',15,false}}} =
- asn1_wrapper:decode('Default','SetIntBool',[49,0]),
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','SeqStrings',
- #'SeqStrings'{a="123456789",
- b1="abcdef",
- b2={0,13},
- b3={"First line",{0,13},"Second line"},
- c="Printable string",
- d={0,0,1,14}}),
-
- ?line {ok,{'SeqStrings',"123456789","abcdef",[0,13],
- ["First line",[0,13],"Second line"],"Printable string",
- [0,0,1,14]}} =
- asn1_wrapper:decode('Default','SeqStrings',[48,0]),
-
- ?line {ok,[49,0]} =
- asn1_wrapper:encode('Default','SetStrings',
- #'SetStrings'{a="123456789",
- b1="abcdef",
- b2={0,13},
- b3={"First line",{0,13},"Second line"},
- c="Printable string",
- d={0,0,1,14}}),
-
- ?line {ok,{'SetStrings',"123456789","abcdef",[0,13],
- ["First line",[0,13],"Second line"],"Printable string",
- [0,0,1,14]}} =
- asn1_wrapper:decode('Default','SetStrings',[49,0]),
-
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','S1',
- #'S1'{a=#'S1_a'{aa=1,
- ab=#'S2'{a=2,b=true}},
- b=#'S4'{a=#'S2'{a=2,b=true},
- b=#'S4_b'{ba=true,
- bb=5}}}),
-
- ?line {ok,{'S1',{'S1_a',1,{'S2',2,true}},
- {'S4',{'S2',2,true},{'S4_b',true,5}}}} =
- asn1_wrapper:decode('Default','S1',[48,0]),
-
- ?line {ok,[48,3,129,1,255]} =
- asn1_wrapper:encode('Default','S2',
- #'S2'{a=1,b=true}),
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','S3',
- #'S3'{a=[11,12,13],
- b=[{a,11},{b,true},{c,13}],
- c=[1,2,3,4],
- d=[#'S2'{a=20,b=true},#'S2'{a=30,b=false}]}),
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','S3',
- #'S3'{a=[11,13,12],
- b=[{b,true},{a,11},{c,13}],
- c=[3,4,1,2],
- d=[#'S2'{a=30,b=false},#'S2'{a=20,b=true}]}),
-
- ?line {ok,[48,0]} = asn1_wrapper:encode('Default','S3',#'S3'{}),
-
- ?line {ok,[49,0]} =
- asn1_wrapper:encode('Default','S3set',
- #'S3set'{a=[{c,#'S2'{a=3,b=true}},
- {b,17},{a,false}],
- b=[1,2,3,4]}),
-
- ?line {ok,[49,0]} =
- asn1_wrapper:encode('Default','S3set',
- #'S3set'{a=[{b,17},{c,#'S2'{a=3,b=true}},
- {a,false}],
- b=[1,3,4,2]}),
-
- ?line {ok,[49,0]} = asn1_wrapper:encode('Default','S3set',#'S3set'{}),
-
- ?line {ok,[48,0]} =
- asn1_wrapper:encode('Default','S4',#'S4'{a={'S2',1,asn1_NOVALUE},
- b=#'S4_b'{ba=true,bb=0}}),
+main(ber, []) ->
+ %% Nothing to test because plain BER will only use
+ %% default values when explicitly told to do so by
+ %% asn1_DEFAULT.
+ ok;
+main(Rule, Opts) ->
+ %% DER, PER, UPER. These encodings should not encode
+ %% values that are equal to the default value.
+
+ case {Rule,Opts} of
+ {ber,[der]} ->
+ der();
+ {_,_} ->
+ ok
+ end,
+
+ Ts = [{#'SeqInts'{},
+ [{#'SeqInts'.c,
+ [asn1_DEFAULT,
+ three,
+ 3]}]},
+
+ {#'SeqBS'{},
+ [{#'SeqBS'.a,
+ [asn1_DEFAULT,
+ 2#0110101,
+ [1,0,1,0,1,1,0],
+ {1,<<16#AC>>},
+ <<1:1,0:1,1:1,0:1,1:1,1:1,0:1>>]},
+ {#'SeqBS'.b,
+ [asn1_DEFAULT,
+ 2#10100010101,
+ [1,0,1,0,1,0,0,0,1,0,1,0],
+ {4,<<16#A8,16#A0>>},
+ <<16#A8:8,16#A:4>>]},
+ {#'SeqBS'.c,
+ [asn1_DEFAULT,
+ [second],
+ [0,1],
+ {6,<<0:1,1:1,0:6>>},
+ <<1:2>>]},
+ {#'SeqBS'.c, %Zeroes on the right
+ [asn1_DEFAULT,
+ [second],
+ [0,1,0,0,0],
+ {4,<<0:1,1:1,0:6>>},
+ <<1:2,0:17>>]},
+ {#'SeqBS'.d,
+ [asn1_DEFAULT,
+ 2#1001,
+ [1,0,0,1],
+ {4,<<2#1001:4,0:4>>},
+ <<2#1001:4>>]},
+ {#'SeqBS'.e,
+ [asn1_DEFAULT,
+ [0,1,0,1,1,0,1,0],
+ {0,<<2#01011010:8>>},
+ <<2#01011010:8>>]},
+ %% Not EQUAL to DEFAULT.
+ {#'SeqBS'.b,
+ [[1,1,0], %Not equal to DEFAULT
+ {5,<<6:3,0:5>>},
+ <<6:3>>]}
+ ]},
+
+ {#'SeqOS'{},
+ [{#'SeqOS'.a,
+ [asn1_DEFAULT,
+ [172]]}]},
+
+ {#'SeqOI'{},
+ [{#'SeqOI'.a,
+ [asn1_DEFAULT,
+ {1,2,14,15}]},
+ {#'SeqOI'.b,
+ [asn1_DEFAULT,
+%% {iso,'member-body',250,3,4},
+ {1,2,250,3,4}]},
+ {#'SeqOI'.c,
+ [asn1_DEFAULT,
+%% {iso,standard,8571,2,250,4},
+ {1,0,8571,2,250,4}]}]}
+ ],
+ io:format("~p\n", [Ts]),
+ R0 = [[consistency(Rec, Pos, Vs) || {Pos,Vs} <- Fs] || {Rec,Fs} <- Ts],
+ case lists:flatten(R0) of
+ [] ->
+ ok;
+ [_|_]=R ->
+ io:format("~p\n", [R]),
+ ?t:fail()
+ end.
+
+consistency(Rec0, Pos, [V|Vs]) ->
+ T = element(1, Rec0),
+ Rec = setelement(Pos, Rec0, V),
+ {ok,Enc} = 'Default':encode(T, Rec),
+ {ok,_SmokeTest} = 'Default':decode(T, Enc),
+ consistency_1(Vs, Rec0, Pos, Enc).
+
+consistency_1([V|Vs], Rec0, Pos, Enc) ->
+ Rec = setelement(Pos, Rec0, V),
+ case 'Default':encode(element(1, Rec), Rec) of
+ {ok,Enc} ->
+ consistency_1(Vs, Rec0, Pos, Enc);
+ {ok,WrongEnc} ->
+ [{Rec,{wrong,WrongEnc},{should_be,Enc}}|
+ consistency_1(Vs, Rec0, Pos, Enc)]
+ end;
+consistency_1([], _, _, _) -> [].
+
+der() ->
+ io:put_chars("Peforming DER-specific tests..."),
+ roundtrip(<<48,0>>,
+ 'SeqInts',
+ #'SeqInts'{a=asn1_DEFAULT,b=asn1_DEFAULT,
+ c=asn1_DEFAULT,d=asn1_DEFAULT},
+ #'SeqInts'{a=1,b=-1,c=3,d=1}),
+ roundtrip(<<48,0>>,
+ 'SeqInts',
+ #'SeqInts'{a=1,b=-1,c=three,d=1},
+ #'SeqInts'{a=1,b=-1,c=3,d=1}),
+
+ roundtrip(<<49,0>>,
+ 'SetInts',
+ #'SetInts'{a=asn1_DEFAULT,b=asn1_DEFAULT,
+ c=asn1_DEFAULT,d=asn1_DEFAULT},
+ #'SetInts'{a=1,b=-1,c=3,d=1}),
+ roundtrip(<<49,0>>,
+ 'SetInts',
+ #'SetInts'{a=1,b=-1,c=three,d=1},
+ #'SetInts'{a=1,b=-1,c=3,d=1}),
+
+
+ roundtrip(<<48,0>>,
+ 'SeqBS',
+ #'SeqBS'{a=2#0110101,
+ b=2#010100010101,
+ c=[second],
+ d=[1,0,0,1]},
+ #'SeqBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>,
+ c=[second], d = <<2#1001:4>>,
+ e = <<2#01011010:8>>}),
+ roundtrip(<<48,0>>,
+ 'SeqBS',
+ #'SeqBS'{a=[1,0,1,0,1,1,0],
+ b=[1,0,1,0,1,0,0,0,1,0,1,0],
+ c={5,<<64>>},
+ d=2#1001},
+ #'SeqBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>,
+ c=[second], d = <<2#1001:4>>,
+ e = <<2#01011010:8>>}),
+ roundtrip(<<48,3,131,1,0>>,
+ 'SeqBS',
+ #'SeqBS'{a=[1,0,1,0,1,1,0],
+ b=[1,0,1,0,1,0,0,0,1,0,1,0],
+ c={5,<<64>>},
+ d=0},
+ #'SeqBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>,
+ c=[second], d = <<>>,
+ e = <<2#01011010:8>>}),
+ roundtrip(<<48,3,131,1,0>>,
+ 'SeqBS',
+ #'SeqBS'{a = <<1:1,0:1,1:1,0:1,1:1,1:1,0:1>>,
+ b = <<1:1,0:1,1:1,0:1,1:1,0:1,0:1,0:1,1:1,0:1,1:1,0:1>>,
+ c = <<2:3>>,
+ d=0,
+ e = <<16#5A:8>>},
+ #'SeqBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>,
+ c=[second], d = <<>>,
+ e = <<2#01011010:8>>}),
+
+ %% None of the default values are used.
+ roundtrip(<<48,19,128,2,7,128,129,2,5,64,130,2,5,32,131,1,0,132,2,5,224>>,
+ 'SeqBS',
+ #'SeqBS'{a = <<1:1>>,
+ b = {5,<<64>>},
+ c = [third],
+ d = 0,
+ e = <<7:3>>},
+ #'SeqBS'{a = <<1:1>>,
+ b = <<2:3>>,
+ c = [third],
+ d = <<>>,
+ e = <<7:3>>}),
+
+ roundtrip(<<49,0>>,
+ 'SetBS',
+ #'SetBS'{a=2#0110101,
+ b=2#010100010101,
+ c=[second],
+ d=[1,0,0,1]},
+ #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>,
+ c=[second], d = <<2#1001:4>>}),
+ roundtrip(<<49,0>>,
+ 'SetBS',
+ #'SetBS'{a=[1,0,1,0,1,1,0],
+ b=[1,0,1,0,1,0,0,0,1,0,1,0],
+ c={5,<<64>>},
+ d=9},
+ #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>,
+ c=[second], d = <<2#1001:4>>}),
+ roundtrip(<<49,3,131,1,0>>,
+ 'SetBS',
+ #'SetBS'{a=[1,0,1,0,1,1,0],
+ b=[1,0,1,0,1,0,0,0,1,0,1,0],
+ c={5,<<64>>},
+ d=0},
+ #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>,
+ c=[second], d = <<>>}),
+ roundtrip(<<49,3,131,1,0>>,
+ 'SetBS',
+ #'SetBS'{a = <<1:1,0:1,1:1,0:1,1:1,1:1,0:1>>,
+ b = <<1:1,0:1,1:1,0:1,1:1,0:1,0:1,0:1,1:1,0:1,1:1,0:1>>,
+ c = <<2:3>>,
+ d=0},
+ #'SetBS'{a = <<2#1010110:7>>, b = <<16#A8A:12>>,
+ c=[second], d = <<>>}),
+
+ roundtrip(<<48,0>>, 'SeqOS',
+ #'SeqOS'{a=[172],b=[16#A8,16#A0],c='NULL'}),
+ roundtrip(<<48,0>>,
+ 'SeqOS',
+ #'SeqOS'{a=172,b=43168,c='NULL'},
+ #'SeqOS'{a=[172],b=[16#A8,16#A0],c='NULL'}),
+
+ roundtrip(<<49,0>>, 'SetOS', #'SetOS'{a=[172],b=[16#A8,16#A0],c='NULL'}),
+ roundtrip(<<49,0>>,
+ 'SetOS',
+ #'SetOS'{a=172,b=43168,c='NULL'},
+ #'SetOS'{a=[172],b=[16#A8,16#A0],c='NULL'}),
+
+ roundtrip(<<48,0>>,
+ 'SeqOI',
+ #'SeqOI'{a={1,2,14,15},
+ b={iso,'member-body',250,3,4},
+ c={iso,standard,8571,2,250,4}},
+ #'SeqOI'{a={1,2,14,15},
+ b={1,2,250,3,4},
+ c={1,0,8571,2,250,4}}),
+
+ roundtrip(<<49,0>>,
+ 'SetOI',
+ #'SetOI'{a={1,2,14,15},
+ b={iso,'member-body',250,3,4},
+ c={iso,standard,8571,2,250,4}},
+ #'SetOI'{a={1,2,14,15},
+ b={1,2,250,3,4},
+ c={1,0,8571,2,250,4}}),
+
+ roundtrip(<<48,0>>, 'SeqEnum', #'SeqEnum'{a=b4,b=b2}),
+ roundtrip(<<49,0>>, 'SetEnum', #'SetEnum'{a=b4,b=b2}),
+
+ roundtrip(<<48,0>>,
+ 'SeqIntBool',
+ #'SeqIntBool'{a=#'SeqIntBool_a'{aa=12,ab=13},
+ b=#'S2'{a=14,b=true},
+ c=#'S2'{a=15,b=false}}),
+ roundtrip(<<48,0>>,
+ 'SeqIntBool',
+ #'SeqIntBool'{a=asn1_DEFAULT,b=asn1_DEFAULT,c=asn1_DEFAULT},
+ #'SeqIntBool'{a=#'SeqIntBool_a'{aa=12,ab=13},
+ b=#'S2'{a=14,b=true},
+ c=#'S2'{a=15,b=false}}),
+
+ roundtrip(<<49,0>>,
+ 'SetIntBool',
+ #'SetIntBool'{a=#'SetIntBool_a'{aa=12,ab=13},
+ b=#'S2'{a=14,b=true},
+ c=#'S2'{a=15,b=false}}),
+ roundtrip(<<49,0>>,
+ 'SetIntBool',
+ #'SetIntBool'{a=asn1_DEFAULT,b=asn1_DEFAULT,c=asn1_DEFAULT},
+ #'SetIntBool'{a=#'SetIntBool_a'{aa=12,ab=13},
+ b=#'S2'{a=14,b=true},
+ c=#'S2'{a=15,b=false}}),
+
+ roundtrip(<<48,0>>,
+ 'SeqStrings',
+ #'SeqStrings'{a="123456789",b1="abcdef",
+ b2={0,13},
+ b3={"First line",{0,13},"Second line"},
+ c="Printable string",
+ d={0,0,1,14}},
+ #'SeqStrings'{a="123456789",b1="abcdef",
+ b2=[0,13],
+ b3=["First line",[0,13],"Second line"],
+ c="Printable string",
+ d=[0,0,1,14]}),
+
+ roundtrip(<<49,0>>,
+ 'SetStrings',
+ #'SetStrings'{a="123456789",b1="abcdef",
+ b2={0,13},
+ b3={"First line",{0,13},"Second line"},
+ c="Printable string",
+ d={0,0,1,14}},
+ #'SetStrings'{a="123456789",b1="abcdef",
+ b2=[0,13],
+ b3=["First line",[0,13],"Second line"],
+ c="Printable string",
+ d=[0,0,1,14]}),
+
+ roundtrip(<<48,0>>,
+ 'S1',
+ #'S1'{a=#'S1_a'{aa=1,ab=#'S2'{a=2,b=true}},
+ b=#'S4'{a=#'S2'{a=2,b=true},b=#'S4_b'{ba=true,bb=5}}}),
+
+ roundtrip(<<48,3,129,1,255>>, 'S2', #'S2'{a=1,b=true}),
+
+ roundtrip(<<48,0>>,
+ 'S3',
+ #'S3'{a="\v\f\r",
+ b=[{a,11},{b,true},{c,13}],
+ c=[1,2,3,4],
+ d=[#'S2'{a=20,b=true},#'S2'{a=30,b=false}]}),
+ roundtrip(<<48,0>>,
+ 'S3',
+ #'S3'{a=[11,13,12],
+ b=[{b,true},{a,11},{c,13}],
+ c=[3,4,1,2],
+ d=[#'S2'{a=30,b=false},#'S2'{a=20,b=true}]},
+ #'S3'{a=[11,12,13],
+ b=[{a,11},{b,true},{c,13}],
+ c=[1,2,3,4],
+ d=[#'S2'{a=20,b=true},#'S2'{a=30,b=false}]}),
+ roundtrip(<<48,0>>,
+ 'S3',
+ #'S3'{a=asn1_DEFAULT,b=asn1_DEFAULT,
+ c=asn1_DEFAULT,d=asn1_DEFAULT},
+ #'S3'{a=[11,12,13],
+ b=[{a,11},{b,true},{c,13}],
+ c=[1,2,3,4],
+ d=[#'S2'{a=20,b=true},#'S2'{a=30,b=false}]}),
+
+ roundtrip(<<49,0>>,
+ 'S3set',
+ #'S3set'{a=[{c,#'S2'{a=3,b=true}},{b,17},{a,false}],
+ b=[1,2,3,4]}),
+ roundtrip(<<49,0>>,
+ 'S3set',
+ #'S3set'{a=[{b,17},{c,#'S2'{a=3,b=true}},{a,false}],
+ b=[1,3,4,2]},
+ #'S3set'{a=[{c,#'S2'{a=3,b=true}},{b,17},{a,false}],
+ b=[1,2,3,4]}),
+ roundtrip(<<49,0>>,
+ 'S3set',
+ #'S3set'{a=asn1_DEFAULT,b=asn1_DEFAULT},
+ #'S3set'{a=[{c,#'S2'{a=3,b=true}},{b,17},{a,false}],
+ b=[1,2,3,4]}),
+
+ roundtrip(<<48,0>>,
+ 'S4',
+ #'S4'{a=#'S2'{a=1,b=asn1_NOVALUE},b=#'S4_b'{ba=true,bb=0}},
+ #'S4'{a=#'S2'{a=1,b=asn1_NOVALUE},b=#'S4_b'{ba=true,bb=0}}),
+
+ ok.
+
+roundtrip(Encoded, Type, Value) ->
+ roundtrip(Encoded, Type, Value, Value).
+
+roundtrip(Encoded, Type, Value, ExpectedValue) ->
+ Encoded = asn1_test_lib:roundtrip_enc('Default', Type,
+ Value, ExpectedValue),
ok.
diff --git a/lib/asn1/test/testSeqSetIndefinite.erl b/lib/asn1/test/testSeqSetIndefinite.erl
new file mode 100644
index 0000000000..6becf84e77
--- /dev/null
+++ b/lib/asn1/test/testSeqSetIndefinite.erl
@@ -0,0 +1,52 @@
+%%
+%% %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(testSeqSetIndefinite).
+-export([main/0]).
+
+-include_lib("test_server/include/test_server.hrl").
+
+main() ->
+ seq_indefinite(),
+ set_indefinite().
+
+seq_indefinite() ->
+ %% normal encoding
+ B = <<48,20,1,1,255,48,9,1,1,255,2,4,251,35,238,194,2,4,251,55,236,161>>,
+ %% indefinite length encoding
+ Bi = <<48,22,1,1,255,48,128,1,1,255,2,4,251,35,238,194,0,0,2,4,251,55,236,161>>,
+ %% the value which is encoded
+ V = {'SeqS3',true,{'SeqS3_seqS3',true,-81531198},-80221023},
+ {ok,V} = 'SeqSetIndefinite':decode('SeqS3', B),
+ {ok,V} = 'SeqSetIndefinite':decode('SeqS3', Bi),
+
+ ok.
+
+set_indefinite() ->
+ %% normal encoding
+ B = <<49,20,1,1,255,49,9,1,1,255,2,4,251,35,238,194,2,4,251,55,236,161>>,
+ %% indefinite length encoding
+ Bi = <<49,22,1,1,255,49,128,1,1,255,2,4,251,35,238,194,0,0,2,4,251,55,236,161>>,
+
+ %% the value which is encoded
+ V = {'SetS3',true,{'SetS3_setS3',true,-81531198},-80221023},
+ {ok,V} = 'SeqSetIndefinite':decode('SetS3', B),
+ {ok,V} = 'SeqSetIndefinite':decode('SetS3', Bi),
+
+ ok.
diff --git a/lib/asn1/test/testSeqTag.erl b/lib/asn1/test/testSeqTag.erl
index 9fdaae35dd..2f127b3e97 100644
--- a/lib/asn1/test/testSeqTag.erl
+++ b/lib/asn1/test/testSeqTag.erl
@@ -35,69 +35,25 @@
-record('Exp',{os, bool}).
main(_Rules) ->
-
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SeqTag','SeqTag',#'SeqTag'{nt = #'NT'{bool = true, os = "kalle"},
- imp = #'Imp'{bool = true, os = "kalle"},
- exp = #'Exp'{bool = true, os = "kalle"}}),
- ?line {ok,{'SeqTag',{'NT',"kalle",true},{'Imp',"kalle",true},{'Exp',"kalle",true}}} =
- asn1_wrapper:decode('SeqTag','SeqTag',lists:flatten(Bytes11)),
-
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SeqTag','SeqTagImp',#'SeqTagImp'{nt = #'NT'{bool = true, os = "kalle"},
- imp = #'Imp'{bool = true, os = "kalle"},
- exp = #'Exp'{bool = true, os = "kalle"}}),
- ?line {ok,{'SeqTagImp',{'NT',"kalle",true},{'Imp',"kalle",true},{'Exp',"kalle",true}}} =
- asn1_wrapper:decode('SeqTag','SeqTagImp',lists:flatten(Bytes12)),
-
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SeqTag','SeqTagExp',#'SeqTagExp'{nt = #'NT'{bool = true, os = "kalle"},
- imp = #'Imp'{bool = true, os = "kalle"},
- exp = #'Exp'{bool = true, os = "kalle"}}),
- ?line {ok,{'SeqTagExp',{'NT',"kalle",true},{'Imp',"kalle",true},{'Exp',"kalle",true}}} =
- asn1_wrapper:decode('SeqTag','SeqTagExp',lists:flatten(Bytes13)),
-
-
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SeqTag','SeqTagX',
- #'SeqTagX'{xnt = #'XSeqNT'{bool = true, os = "kalle"},
- ximp = #'XSeqImp'{bool = true, os = "kalle"},
- xexp = #'XSeqExp'{bool = true, os = "kalle"}}),
- ?line {ok,{'SeqTagX',{'XSeqNT',"kalle",true},
- {'XSeqImp',"kalle",true},
- {'XSeqExp',"kalle",true}}} =
- asn1_wrapper:decode('SeqTag','SeqTagX',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SeqTag','SeqTagImpX',
- #'SeqTagImpX'{xnt = #'XSeqNT'{bool = true, os = "kalle"},
- ximp = #'XSeqImp'{bool = true, os = "kalle"},
- xexp = #'XSeqExp'{bool = true, os = "kalle"}}),
- ?line {ok,{'SeqTagImpX',{'XSeqNT',"kalle",true},
- {'XSeqImp',"kalle",true},
- {'XSeqExp',"kalle",true}}} =
- asn1_wrapper:decode('SeqTag','SeqTagImpX',lists:flatten(Bytes22)),
-
-
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('SeqTag','SeqTagExpX',
- #'SeqTagExpX'{xnt = #'XSeqNT'{bool = true, os = "kalle"},
- ximp = #'XSeqImp'{bool = true, os = "kalle"},
- xexp = #'XSeqExp'{bool = true, os = "kalle"}}),
- ?line {ok,{'SeqTagExpX',{'XSeqNT',"kalle",true},
- {'XSeqImp',"kalle",true},
- {'XSeqExp',"kalle",true}}} =
- asn1_wrapper:decode('SeqTag','SeqTagExpX',lists:flatten(Bytes23)),
-
-
-
-
-
+ roundtrip('SeqTag', #'SeqTag'{nt=#'NT'{os="kalle",bool=true},
+ imp=#'Imp'{os="kalle",bool=true},
+ exp=#'Exp'{os="kalle",bool=true}}),
+ roundtrip('SeqTagImp', #'SeqTagImp'{nt=#'NT'{os="kalle",bool=true},
+ imp=#'Imp'{os="kalle",bool=true},
+ exp=#'Exp'{os="kalle",bool=true}}),
+ roundtrip('SeqTagExp', #'SeqTagExp'{nt=#'NT'{os="kalle",bool=true},
+ imp=#'Imp'{os="kalle",bool=true},
+ exp=#'Exp'{os="kalle",bool=true}}),
+ roundtrip('SeqTagX', #'SeqTagX'{xnt=#'XSeqNT'{os="kalle",bool=true},
+ ximp=#'XSeqImp'{os="kalle",bool=true},
+ xexp=#'XSeqExp'{os="kalle",bool=true}}),
+ roundtrip('SeqTagImpX', #'SeqTagImpX'{xnt=#'XSeqNT'{os="kalle",bool=true},
+ ximp=#'XSeqImp'{os="kalle",bool=true},
+ xexp=#'XSeqExp'{os="kalle",bool=true}}),
+ roundtrip('SeqTagExpX', #'SeqTagExpX'{xnt=#'XSeqNT'{os="kalle",bool=true},
+ ximp=#'XSeqImp'{os="kalle",bool=true},
+ xexp=#'XSeqExp'{os="kalle",bool=true}}),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SeqTag', T, V).
diff --git a/lib/asn1/test/testSeqTypeRefCho.erl b/lib/asn1/test/testSeqTypeRefCho.erl
index 4b9eac7034..b008bc46b8 100644
--- a/lib/asn1/test/testSeqTypeRefCho.erl
+++ b/lib/asn1/test/testSeqTypeRefCho.erl
@@ -27,17 +27,12 @@
-record('SeqTRcho',{seqCho, seqChoE, 'seqCho-E', 'seqChoE-E'}).
main(_Rules) ->
-
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SeqTypeRefCho','SeqTRcho',
- #'SeqTRcho'{'seqCho' = {choOs,"A string 1"},
- 'seqChoE' = {choOs,"A string 3"},
- 'seqCho-E' = {choOs,"A string 7"},
- 'seqChoE-E' = {choOs,"A string 9"}}),
- ?line {ok,{'SeqTRcho',{choOs,"A string 1"},{choOs,"A string 3"},{choOs,"A string 7"},{choOs,"A string 9"}}} =
- asn1_wrapper:decode('SeqTypeRefCho','SeqTRcho',lists:flatten(Bytes11)),
-
-
-
+ roundtrip('SeqTRcho',
+ #'SeqTRcho'{'seqCho' = {choOs,"A string 1"},
+ 'seqChoE' = {choOs,"A string 3"},
+ 'seqCho-E' = {choOs,"A string 7"},
+ 'seqChoE-E' = {choOs,"A string 9"}}),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SeqTypeRefCho', T, V).
diff --git a/lib/asn1/test/testSeqTypeRefPrim.erl b/lib/asn1/test/testSeqTypeRefPrim.erl
index 7d4c2acc0e..b63882ae99 100644
--- a/lib/asn1/test/testSeqTypeRefPrim.erl
+++ b/lib/asn1/test/testSeqTypeRefPrim.erl
@@ -18,40 +18,24 @@
%%
%%
-module(testSeqTypeRefPrim).
-
--export([compile/3]).
-export([main/1]).
-include_lib("test_server/include/test_server.hrl").
-record('SeqTR',{octStr, octStrI, octStrE, 'octStr-I', 'octStrI-I', 'octStrE-I', 'octStr-E', 'octStrI-E', 'octStrE-E'}).
-
-compile(Config,Rules,Options) ->
-
- ?line DataDir = ?config(data_dir,Config),
- ?line OutDir = ?config(priv_dir,Config),
- ?line true = code:add_patha(?config(priv_dir,Config)),
- ?line ok = asn1ct:compile(DataDir ++ "SeqTypeRefPrim",[Rules,{outdir,OutDir}]++Options).
-
-
-
main(_Rules) ->
-
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SeqTypeRefPrim','SeqTR',#'SeqTR'{'octStr' = "A string 1",
- 'octStrI' = "A string 2",
- 'octStrE' = "A string 3",
- 'octStr-I' = "A string 4",
- 'octStrI-I' = "A string 5",
- 'octStrE-I' = "A string 6",
- 'octStr-E' = "A string 7",
- 'octStrI-E' = "A string 8",
- 'octStrE-E' = "A string 9"}) ,
- ?line {ok,{'SeqTR',"A string 1","A string 2","A string 3","A string 4","A string 5","A string 6","A string 7","A string 8","A string 9"}} =
- asn1_wrapper:decode('SeqTypeRefPrim','SeqTR',lists:flatten(Bytes11)),
-
-
-
+ roundtrip('SeqTR',
+ #'SeqTR'{'octStr' = "A string 1",
+ 'octStrI' = "A string 2",
+ 'octStrE' = "A string 3",
+ 'octStr-I' = "A string 4",
+ 'octStrI-I' = "A string 5",
+ 'octStrE-I' = "A string 6",
+ 'octStr-E' = "A string 7",
+ 'octStrI-E' = "A string 8",
+ 'octStrE-E' = "A string 9"}),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SeqTypeRefPrim', T, V).
diff --git a/lib/asn1/test/testSeqTypeRefSeq.erl b/lib/asn1/test/testSeqTypeRefSeq.erl
index 57ec6c19b1..fc2e0a67c9 100644
--- a/lib/asn1/test/testSeqTypeRefSeq.erl
+++ b/lib/asn1/test/testSeqTypeRefSeq.erl
@@ -44,133 +44,43 @@
-record('SeqSeqExp',{seqInt, seqOs}).
-
main(_Rules) ->
-
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SeqTypeRefSeq','Seq1',#'Seq1'{bool1 = true,
- int1 = 15,
- seq1 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'Seq1',true,15,{'SeqIn',true,66}}} =
- asn1_wrapper:decode('SeqTypeRefSeq','Seq1',lists:flatten(Bytes11)),
-
-
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SeqTypeRefSeq','Seq2',#'Seq2'{seq2 = #'SeqIn'{boolIn = true,
- intIn = 66},
- bool2 = true,
- int2 = 15}),
- ?line {ok,{'Seq2',{'SeqIn',true,66},true,15}} =
- asn1_wrapper:decode('SeqTypeRefSeq','Seq2',lists:flatten(Bytes12)),
-
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SeqTypeRefSeq','Seq3',#'Seq3'{bool3 = true,
- seq3 = #'SeqIn'{boolIn = true,
- intIn = 66},
- int3 = 15}),
- ?line {ok,{'Seq3',true,{'SeqIn',true,66},15}} =
- asn1_wrapper:decode('SeqTypeRefSeq','Seq3',lists:flatten(Bytes13)),
-
-
-
- ?line {ok,Bytes14} =
- asn1_wrapper:encode('SeqTypeRefSeq','Seq4',#'Seq4'{seq41 = #'SeqIn'{boolIn = true,
- intIn = 66},
- seq42 = #'SeqIn'{boolIn = true,
- intIn = 66},
- seq43 = #'SeqIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'Seq4',{'SeqIn',true,66},{'SeqIn',true,66},{'SeqIn',true,66}}} =
- asn1_wrapper:decode('SeqTypeRefSeq','Seq4',lists:flatten(Bytes14)),
-
-
-
-
-
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SeqTypeRefSeq','SeqS1',#'SeqS1'{boolS1 = true,
- intS1 = 15,
- seqS1 = #'SeqS1_seqS1'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SeqS1',true,15,{'SeqS1_seqS1',true,66}}} =
- asn1_wrapper:decode('SeqTypeRefSeq','SeqS1',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SeqTypeRefSeq','SeqS2',#'SeqS2'{seqS2 = #'SeqS2_seqS2'{boolIn = true,
- intIn = 66},
- boolS2 = true,
- intS2 = 15}),
- ?line {ok,{'SeqS2',{'SeqS2_seqS2',true,66},true,15}} =
- asn1_wrapper:decode('SeqTypeRefSeq','SeqS2',lists:flatten(Bytes22)),
-
-
-
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('SeqTypeRefSeq','SeqS3',#'SeqS3'{boolS3 = true,
- seqS3 = #'SeqS3_seqS3'{boolIn = true,
- intIn = 66},
- intS3 = 15}),
- ?line {ok,{'SeqS3',true,{'SeqS3_seqS3',true,66},15}} =
- asn1_wrapper:decode('SeqTypeRefSeq','SeqS3',lists:flatten(Bytes23)),
-
-
-
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SeqTypeRefSeq','SeqSTag',#'SeqSTag'{seqS1 = #'SeqSTag_seqS1'{b1 = true,
- i1 = 11},
- seqS2 = #'SeqSTag_seqS2'{b2 = true,
- i2 = 22},
- seqS3 = #'SeqSTag_seqS3'{b3 = true,
- i3 = 33}}),
- ?line {ok,{'SeqSTag',{'SeqSTag_seqS1',true,11},
- {'SeqSTag_seqS2',true,22},
- {'SeqSTag_seqS3',true,33}}} =
- asn1_wrapper:decode('SeqTypeRefSeq','SeqSTag',lists:flatten(Bytes31)),
-
-
-
-
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SeqTypeRefSeq','SeqTRseq',
- #'SeqTRseq'{'seqSeq' = #'SeqSeq'{seqOs = "A1",
- seqInt = 2},
- 'seqSeqI' = #'SeqSeq'{seqOs = "A2",
- seqInt = 2},
- 'seqSeqE' = #'SeqSeq'{seqOs = "A3",
- seqInt = 2},
- 'seqSeq-I' = #'SeqSeqImp'{seqOs = "A4",
- seqInt = 2},
- 'seqSeqI-I' = #'SeqSeqImp'{seqOs = "A5",
- seqInt = 2},
- 'seqSeqE-I' = #'SeqSeqImp'{seqOs = "A6",
- seqInt = 2},
- 'seqSeq-E' = #'SeqSeqExp'{seqOs = "A7",
- seqInt = 2},
- 'seqSeqI-E' = #'SeqSeqExp'{seqOs = "A8",
- seqInt = 2},
- 'seqSeqE-E' = #'SeqSeqExp'{seqOs = "A9",
- seqInt = 2}}),
- ?line {ok,{'SeqTRseq',{'SeqSeq',2,"A1"},
- {'SeqSeq',2,"A2"},
- {'SeqSeq',2,"A3"},
- {'SeqSeqImp',2,"A4"},
- {'SeqSeqImp',2,"A5"},
- {'SeqSeqImp',2,"A6"},
- {'SeqSeqExp',2,"A7"},
- {'SeqSeqExp',2,"A8"},
- {'SeqSeqExp',2,"A9"}}} =
- asn1_wrapper:decode('SeqTypeRefSeq','SeqTRseq',lists:flatten(Bytes41)),
-
+ roundtrip('Seq1',
+ #'Seq1'{bool1=true,int1=15,
+ seq1=#'SeqIn'{boolIn=true,intIn=66}}),
+ roundtrip('Seq2',
+ #'Seq2'{seq2=#'SeqIn'{boolIn=true,intIn=66},
+ bool2=true,int2=15}),
+ roundtrip('Seq3',
+ #'Seq3'{bool3=true,seq3=#'SeqIn'{boolIn=true,intIn=66},int3=15}),
+ roundtrip('Seq4',
+ #'Seq4'{seq41=#'SeqIn'{boolIn=true,intIn=66},
+ seq42=#'SeqIn'{boolIn=true,intIn=66},
+ seq43=#'SeqIn'{boolIn=true,intIn=66}}),
+ roundtrip('SeqS1',
+ #'SeqS1'{boolS1=true,intS1=15,
+ seqS1=#'SeqS1_seqS1'{boolIn=true,intIn=66}}),
+ roundtrip('SeqS2',
+ #'SeqS2'{seqS2=#'SeqS2_seqS2'{boolIn=true,intIn=66},
+ boolS2=true,intS2=15}),
+ roundtrip('SeqS3',
+ #'SeqS3'{boolS3=true,seqS3=#'SeqS3_seqS3'{boolIn=true,intIn=66},
+ intS3=15}),
+ roundtrip('SeqSTag',
+ #'SeqSTag'{seqS1=#'SeqSTag_seqS1'{b1=true,i1=11},
+ seqS2=#'SeqSTag_seqS2'{b2=true,i2=22},
+ seqS3=#'SeqSTag_seqS3'{b3=true,i3=33}}),
+ roundtrip('SeqTRseq',
+ #'SeqTRseq'{seqSeq=#'SeqSeq'{seqInt=2,seqOs="A1"},
+ seqSeqI=#'SeqSeq'{seqInt=2,seqOs="A2"},
+ seqSeqE=#'SeqSeq'{seqInt=2,seqOs="A3"},
+ 'seqSeq-I'=#'SeqSeqImp'{seqInt=2,seqOs="A4"},
+ 'seqSeqI-I'=#'SeqSeqImp'{seqInt=2,seqOs="A5"},
+ 'seqSeqE-I'=#'SeqSeqImp'{seqInt=2,seqOs="A6"},
+ 'seqSeq-E'=#'SeqSeqExp'{seqInt=2,seqOs="A7"},
+ 'seqSeqI-E'=#'SeqSeqExp'{seqInt=2,seqOs="A8"},
+ 'seqSeqE-E'=#'SeqSeqExp'{seqInt=2,seqOs="A9"}}),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SeqTypeRefSeq', T, V).
diff --git a/lib/asn1/test/testSeqTypeRefSet.erl b/lib/asn1/test/testSeqTypeRefSet.erl
index c06a0e7a2b..911a4b7a47 100644
--- a/lib/asn1/test/testSeqTypeRefSet.erl
+++ b/lib/asn1/test/testSeqTypeRefSet.erl
@@ -31,36 +31,17 @@
main(_Rules) ->
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SeqTypeRefSet','SeqTRset',
- #'SeqTRset'{'seqSet' = #'SeqSet'{setOs = "A1",
- setInt = 2},
- 'seqSetI' = #'SeqSet'{setOs = "A2",
- setInt = 2},
- 'seqSetE' = #'SeqSet'{setOs = "A3",
- setInt = 2},
- 'seqSet-I' = #'SeqSetImp'{setOs = "A4",
- setInt = 2},
- 'seqSetI-I' = #'SeqSetImp'{setOs = "A5",
- setInt = 2},
- 'seqSetE-I' = #'SeqSetImp'{setOs = "A6",
- setInt = 2},
- 'seqSet-E' = #'SeqSetExp'{setOs = "A7",
- setInt = 2},
- 'seqSetI-E' = #'SeqSetExp'{setOs = "A8",
- setInt = 2},
- 'seqSetE-E' = #'SeqSetExp'{setOs = "A9",
- setInt = 2}}),
- ?line {ok,{'SeqTRset',{'SeqSet',2,"A1"},
- {'SeqSet',2,"A2"},
- {'SeqSet',2,"A3"},
- {'SeqSetImp',2,"A4"},
- {'SeqSetImp',2,"A5"},
- {'SeqSetImp',2,"A6"},
- {'SeqSetExp',2,"A7"},
- {'SeqSetExp',2,"A8"},
- {'SeqSetExp',2,"A9"}}} =
- asn1_wrapper:decode('SeqTypeRefSet','SeqTRset',lists:flatten(Bytes41)),
-
+ roundtrip('SeqTRset',
+ #'SeqTRset'{seqSet=#'SeqSet'{setInt=2,setOs="A1"},
+ seqSetI=#'SeqSet'{setInt=2,setOs="A2"},
+ seqSetE=#'SeqSet'{setInt=2,setOs="A3"},
+ 'seqSet-I'=#'SeqSetImp'{setInt=2,setOs="A4"},
+ 'seqSetI-I'=#'SeqSetImp'{setInt=2,setOs="A5"},
+ 'seqSetE-I'=#'SeqSetImp'{setInt=2,setOs="A6"},
+ 'seqSet-E'=#'SeqSetExp'{setInt=2,setOs="A7"},
+ 'seqSetI-E'=#'SeqSetExp'{setInt=2,setOs="A8"},
+ 'seqSetE-E'=#'SeqSetExp'{setInt=2,setOs="A9"}}),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SeqTypeRefSet', T, V).
diff --git a/lib/asn1/test/testSetDefault.erl b/lib/asn1/test/testSetDefault.erl
index 8aa205e0f0..055dc6cecf 100644
--- a/lib/asn1/test/testSetDefault.erl
+++ b/lib/asn1/test/testSetDefault.erl
@@ -26,58 +26,34 @@
-record('SetDef1',{bool1 = asn1_DEFAULT, int1, set1 = asn1_DEFAULT}).
-record('SetDef2',{set2 = asn1_DEFAULT, bool2, int2}).
-record('SetDef3',{bool3 = asn1_DEFAULT, set3 = asn1_DEFAULT, int3 = asn1_DEFAULT}).
--record('SetIn',{boolIn, intIn}).
+-record('SetIn', {boolIn = asn1_NOVALUE, intIn = 12}).
main(_Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SetDefault','SetDef1',#'SetDef1'{bool1 = true,
- int1 = 15,
- set1 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SetDef1',true,15,{'SetIn',true,66}}} =
- asn1_wrapper:decode('SetDefault','SetDef1',lists:flatten(Bytes11)),
-
-
- ?line {ok,Bytes12} = asn1_wrapper:encode('SetDefault','SetDef1',#'SetDef1'{int1 = 15}),
- ?line {ok,{'SetDef1',true,15,{'SetIn',asn1_NOVALUE,12}}} =
- asn1_wrapper:decode('SetDefault','SetDef1',lists:flatten(Bytes12)),
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SetDefault','SetDef2',#'SetDef2'{bool2 = true,
- int2 = 15,
- set2 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SetDef2',{'SetIn',true,66},true,15}} =
- asn1_wrapper:decode('SetDefault','SetDef2',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} = asn1_wrapper:encode('SetDefault','SetDef2',#'SetDef2'{bool2 = true,
- int2 = 15}),
- ?line {ok,{'SetDef2',{'SetIn',asn1_NOVALUE,12},true,15}} =
- asn1_wrapper:decode('SetDefault','SetDef2',lists:flatten(Bytes22)),
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SetDefault','SetDef3',#'SetDef3'{bool3 = true,
- int3 = 15,
- set3 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SetDef3',true,{'SetIn',true,66},15}} =
- asn1_wrapper:decode('SetDefault','SetDef3',lists:flatten(Bytes31)),
-
-
- ?line {ok,Bytes32} = asn1_wrapper:encode('SetDefault','SetDef3',#'SetDef3'{int3 = 15}),
- ?line {ok,{'SetDef3',true,{'SetIn',asn1_NOVALUE,12},15}} =
- asn1_wrapper:decode('SetDefault','SetDef3',lists:flatten(Bytes32)),
-
-
-
-
+ roundtrip('SetDef1',
+ #'SetDef1'{bool1=true,int1=15,
+ set1=#'SetIn'{boolIn=true,intIn=66}}),
+ roundtrip('SetDef1',
+ #'SetDef1'{bool1=asn1_DEFAULT,int1=15,set1=asn1_DEFAULT},
+ #'SetDef1'{bool1=true,int1=15,set1=#'SetIn'{}}),
-
-
+ roundtrip('SetDef2',
+ #'SetDef2'{set2=#'SetIn'{boolIn=true,intIn=66},
+ bool2=true,int2=15}),
+ roundtrip('SetDef2',
+ #'SetDef2'{set2=asn1_DEFAULT,bool2=true,int2=15},
+ #'SetDef2'{set2=#'SetIn'{},bool2=true,int2=15}),
+
+ roundtrip('SetDef3',
+ #'SetDef3'{bool3=true,set3=#'SetIn'{boolIn=true,intIn=66},
+ int3=15}),
+ roundtrip('SetDef3',
+ #'SetDef3'{bool3=asn1_DEFAULT,set3=asn1_DEFAULT,int3=15},
+ #'SetDef3'{bool3=true,set3=#'SetIn'{},int3=15}),
ok.
+
+roundtrip(Type, Value) ->
+ roundtrip(Type, Value, Value).
+
+roundtrip(Type, Value, ExpectedValue) ->
+ asn1_test_lib:roundtrip('SetDefault', Type, Value, ExpectedValue).
diff --git a/lib/asn1/test/testSetExtension.erl b/lib/asn1/test/testSetExtension.erl
index c7fb3b42c4..4e2463326b 100644
--- a/lib/asn1/test/testSetExtension.erl
+++ b/lib/asn1/test/testSetExtension.erl
@@ -18,10 +18,7 @@
%%
%%
-module(testSetExtension).
-
-
-include("External.hrl").
--export([compile/3]).
-export([main/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -31,76 +28,20 @@
-record('SetExt3',{bool, int}).
-record('SetExt4',{bool, int}).
-
-compile(Config,Rules,Options) ->
-
- ?line DataDir = ?config(data_dir,Config),
- ?line OutDir = ?config(priv_dir,Config),
- ?line true = code:add_patha(?config(priv_dir,Config)),
- ?line ok = asn1ct:compile(DataDir ++ "SetExtension",
- [Rules,{outdir,OutDir}]++Options).
-
-
-
main(_Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SetExtension','SetExt1',#'SetExt1'{}),
- ?line {ok,{'SetExt1'}} =
- asn1_wrapper:decode('SetExtension','SetExt1',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SetExtension','SetExt2',#'SetExt2'{bool = true,int = 99}),
- ?line {ok,{'SetExt2',true,99}} =
- asn1_wrapper:decode('SetExtension','SetExt2',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SetExtension','SetExt2',#'SetExt2'{int = 99,bool = true}),
- ?line {ok,{'SetExt2',true,99}} =
- asn1_wrapper:decode('SetExtension','SetExt2',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SetExtension','SetExt3',#'SetExt3'{bool = true,int = 99}),
- ?line {ok,{'SetExt3',true,99}} =
- asn1_wrapper:decode('SetExtension','SetExt3',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} =
- asn1_wrapper:encode('SetExtension','SetExt3',#'SetExt3'{int = 99,bool = true}),
- ?line {ok,{'SetExt3',true,99}} =
- asn1_wrapper:decode('SetExtension','SetExt3',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SetExtension','SetExt4',#'SetExt4'{bool = true,int = 99}),
- ?line {ok,{'SetExt4',true,99}} =
- asn1_wrapper:decode('SetExtension','SetExt4',lists:flatten(Bytes41)),
-
- ?line {ok,Bytes42} =
- asn1_wrapper:encode('SetExtension','SetExt4',#'SetExt4'{int = 99,bool = true}),
- ?line {ok,{'SetExt4',true,99}} =
- asn1_wrapper:decode('SetExtension','SetExt4',lists:flatten(Bytes42)),
-
-
- %% Test of extension , needs to be improved and extended
-
- ?line {ok,BytesX11} =
- asn1_wrapper:encode('SetExtension','SetExt1',#'SetExt1'{}),
- ?line {ok,{'SetExt1'}} =
- asn1_wrapper:decode('SetExtension','SetExt1',lists:flatten(BytesX11)),
-
- ?line {ok,BytesX21} =
- asn1_wrapper:encode('SetExtension','SetExt2',#'SetExt2'{bool = true,int = 99}),
- ?line {ok,{'SetExt2',true,99}} =
- asn1_wrapper:decode('SetExtension','SetExt2',lists:flatten(BytesX21)),
-
- ?line {ok,BytesX22} =
- asn1_wrapper:encode('SetExtension','SetExt2',#'SetExt2'{int = 99,bool = true}),
- ?line {ok,{'SetExt2',true,99}} =
- asn1_wrapper:decode('SetExtension','SetExt2',lists:flatten(BytesX22)),
-
-
-
-
-
+ roundtrip('SetExt1', #'SetExt1'{}),
+ roundtrip('SetExt2', #'SetExt2'{bool=true,int=99}),
+ roundtrip('SetExt2', #'SetExt2'{bool=true,int=99}),
+ roundtrip('SetExt3', #'SetExt3'{bool=true,int=99}),
+ roundtrip('SetExt3', #'SetExt3'{bool=true,int=99}),
+ roundtrip('SetExt4', #'SetExt4'{bool=true,int=99}),
+ roundtrip('SetExt4', #'SetExt4'{bool=true,int=99}),
+ roundtrip('SetExt1', #'SetExt1'{}),
+ roundtrip('SetExt2', #'SetExt2'{bool=true,int=99}),
+ roundtrip('SetExt2', #'SetExt2'{bool=true,int=99}),
ok.
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SetExtension', T, V).
+
diff --git a/lib/asn1/test/testSetExternal.erl b/lib/asn1/test/testSetExternal.erl
index 30cddcacfb..e17d7053aa 100644
--- a/lib/asn1/test/testSetExternal.erl
+++ b/lib/asn1/test/testSetExternal.erl
@@ -18,111 +18,36 @@
%%
%%
-module(testSetExternal).
-
--include("External.hrl").
-export([main/1]).
+-include("External.hrl").
-include_lib("test_server/include/test_server.hrl").
-
-record('SetXSeq1',{seq, bool, int}).
-record('SetXSeq2',{bool, seq, int}).
-record('SetXSeq3',{bool, int, seq}).
-%-record('NT',{os, bool}).
-%-record('Imp',{os, bool}).
-%-record('Exp',{os, bool}).
main(_Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SetExternal','XNTNT',#'XSetNT'{bool = true, os = "kalle"}),
- ?line {ok,{'XSetNT',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SetExternal','XNTNT',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SetExternal','XImpNT',#'XSetNT'{bool = true, os = "kalle"}),
- ?line {ok,{'XSetNT',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SetExternal','XImpNT',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SetExternal','XExpNT',#'XSetNT'{bool = true, os = "kalle"}),
- ?line {ok,{'XSetNT',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SetExternal','XExpNT',lists:flatten(Bytes13)),
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SetExternal','XNTImp',#'XSetImp'{bool = true, os = "kalle"}),
- ?line {ok,{'XSetImp',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SetExternal','XNTImp',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SetExternal','XImpImp',#'XSetImp'{bool = true, os = "kalle"}),
- ?line {ok,{'XSetImp',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SetExternal','XImpImp',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('SetExternal','XExpImp',#'XSetImp'{bool = true, os = "kalle"}),
- ?line {ok,{'XSetImp',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SetExternal','XExpImp',lists:flatten(Bytes23)),
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SetExternal','XNTExp',#'XSetExp'{bool = true, os = "kalle"}),
- ?line {ok,{'XSetExp',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SetExternal','XNTExp',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} =
- asn1_wrapper:encode('SetExternal','XImpExp',#'XSetExp'{bool = true, os = "kalle"}),
- ?line {ok,{'XSetExp',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SetExternal','XImpExp',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes33} =
- asn1_wrapper:encode('SetExternal','XExpExp',#'XSetExp'{bool = true, os = "kalle"}),
- ?line {ok,{'XSetExp',[107,97,108,108,101],true}} =
- asn1_wrapper:decode('SetExternal','XExpExp',lists:flatten(Bytes33)),
-
-
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SetExternal','SetXSeq1',
- #'SetXSeq1'{bool = true,
- int = 66,
- seq = #'XSeq1'{bool1 = true,
- int1 = 77,
- seq1 = #'XSeqIn'{boolIn = false,
- intIn = 88}}}),
- ?line {ok,{'SetXSeq1',{'XSeq1',true,77,{'XSeqIn',false,88}},true,66}} =
- asn1_wrapper:decode('SetExternal','SetXSeq1',lists:flatten(Bytes41)),
-
-
-
- ?line {ok,Bytes42} =
- asn1_wrapper:encode('SetExternal','SetXSeq2',
- #'SetXSeq2'{bool = true,
- int = 66,
- seq = #'XSeq1'{bool1 = true,
- int1 = 77,
- seq1 = #'XSeqIn'{boolIn = false,
- intIn = 88}}}),
- ?line {ok,{'SetXSeq2',true,{'XSeq1',true,77,{'XSeqIn',false,88}},66}} =
- asn1_wrapper:decode('SetExternal','SetXSeq2',lists:flatten(Bytes42)),
-
- ?line {ok,Bytes43} =
- asn1_wrapper:encode('SetExternal','SetXSeq3',
- #'SetXSeq3'{bool = true,
- int = 66,
- seq = #'XSeq1'{bool1 = true,
- int1 = 77,
- seq1 = #'XSeqIn'{boolIn = false,
- intIn = 88}}}),
- ?line {ok,{'SetXSeq3',true,66,{'XSeq1',true,77,{'XSeqIn',false,88}}}} =
- asn1_wrapper:decode('SetExternal','SetXSeq3',lists:flatten(Bytes43)),
-
-
-
-
+ roundtrip('XNTNT', #'XSetNT'{os="kalle",bool=true}),
+ roundtrip('XImpNT', #'XSetNT'{os="kalle",bool=true}),
+ roundtrip('XExpNT', #'XSetNT'{os="kalle",bool=true}),
+ roundtrip('XNTImp', #'XSetImp'{os="kalle",bool=true}),
+ roundtrip('XImpImp', #'XSetImp'{os="kalle",bool=true}),
+ roundtrip('XExpImp', #'XSetImp'{os="kalle",bool=true}),
+ roundtrip('XNTExp', #'XSetExp'{os="kalle",bool=true}),
+ roundtrip('XImpExp', #'XSetExp'{os="kalle",bool=true}),
+ roundtrip('XExpExp', #'XSetExp'{os="kalle",bool=true}),
+ roundtrip('SetXSeq1', #'SetXSeq1'{seq=#'XSeq1'{bool1=true,int1=77,
+ seq1=#'XSeqIn'{boolIn=false,intIn=88}},
+ bool=true,int=66}),
+ roundtrip('SetXSeq2', #'SetXSeq2'{bool=true,
+ seq=#'XSeq1'{bool1=true,int1=77,
+ seq1=#'XSeqIn'{boolIn=false,intIn=88}},
+ int=66}),
+ roundtrip('SetXSeq3', #'SetXSeq3'{bool=true,int=66,
+ seq=#'XSeq1'{bool1=true,int1=77,
+ seq1=#'XSeqIn'{boolIn=false,intIn=88}}}),
ok.
-
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SetExternal', T, V).
diff --git a/lib/asn1/test/testSetIndefinite.erl b/lib/asn1/test/testSetIndefinite.erl
deleted file mode 100644
index 73006da62b..0000000000
--- a/lib/asn1/test/testSetIndefinite.erl
+++ /dev/null
@@ -1,41 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-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%
-%%
-%%
--module(testSetIndefinite).
-
--export([main/1]).
-
--include_lib("test_server/include/test_server.hrl").
-
-
-main(per) -> ok;
-main(ber) ->
-
- %% normal encoding
- B = [49,20,1,1,255,49,9,1,1,255,2,4,251,35,238,194,2,4,251,55,236,161],
- %% indefinite length encoding
- Bi = [49,22,1,1,255,49,128,1,1,255,2,4,251,35,238,194,0,0,2,4,251,55,236,161],
- %% the value which is encoded
- V = {'SetS3',true,{'SetS3_setS3',true,-81531198},-80221023},
- ?line {ok,V} = asn1_wrapper:decode('SeqSetIndefinite','SetS3',B),
- ?line {ok,V} = asn1_wrapper:decode('SeqSetIndefinite','SetS3',Bi),
- ok.
-
-
-
diff --git a/lib/asn1/test/testSetOf.erl b/lib/asn1/test/testSetOf.erl
index 08723fb468..54c42c1f21 100644
--- a/lib/asn1/test/testSetOf.erl
+++ b/lib/asn1/test/testSetOf.erl
@@ -28,198 +28,108 @@
-record('Set3',{bool3, set3 = asn1_DEFAULT, int3}).
-record('Set4',{set41 = asn1_DEFAULT, set42 = asn1_DEFAULT, set43 = asn1_DEFAULT}).
-record('SetIn',{boolIn, intIn}).
-%-record('SetCho',{bool1, int1, set1 = asn1_DEFAULT}).
-%-record('SetChoInline',{bool1, int1, set1 = asn1_DEFAULT}).
-%-record('SetChoOfInline_SETOF',{bool1, int1, set1 = asn1_DEFAULT}).
-record('SetEmp',{set1}).
-record('Empty',{}).
main(_Rules) ->
+ roundtrip('Set1',
+ #'Set1'{bool1=true,int1=17,set1=asn1_DEFAULT},
+ #'Set1'{bool1=true,int1=17,set1=[]}),
+ roundtrip('Set1',
+ #'Set1'{bool1=true,int1=17,
+ set1=[#'SetIn'{boolIn=true,intIn=25}]}),
+ roundtrip('Set1', #'Set1'{bool1=true,int1=17,
+ set1=[#'SetIn'{boolIn=true,intIn=25},
+ #'SetIn'{boolIn=false,intIn=125},
+ #'SetIn'{boolIn=false,intIn=225}]}),
+
+ roundtrip('Set2',
+ #'Set2'{set2=asn1_DEFAULT,bool2=true,int2=17},
+ #'Set2'{set2=[],bool2=true,int2=17}),
+ roundtrip('Set2',
+ #'Set2'{set2=[#'SetIn'{boolIn=true,intIn=25}],
+ bool2=true,int2=17}),
+ roundtrip('Set2',
+ #'Set2'{set2=[#'SetIn'{boolIn=true,intIn=25},
+ #'SetIn'{boolIn=false,intIn=125},
+ #'SetIn'{boolIn=false,intIn=225}],
+ bool2=true,int2=17}),
+
+ roundtrip('Set3',
+ #'Set3'{bool3=true,set3=asn1_DEFAULT,int3=17},
+ #'Set3'{bool3=true,set3=[],int3=17}),
+ roundtrip('Set3',
+ #'Set3'{bool3=true,set3=[#'SetIn'{boolIn=true,intIn=25}],
+ int3=17}),
+ roundtrip('Set3',
+ #'Set3'{bool3=true,
+ set3=[#'SetIn'{boolIn=true,intIn=25},
+ #'SetIn'{boolIn=false,intIn=125},
+ #'SetIn'{boolIn=false,intIn=225}],
+ int3=17}),
+
+ roundtrip('Set4',
+ #'Set4'{set41=asn1_DEFAULT,set42=asn1_DEFAULT,
+ set43=asn1_DEFAULT},
+ #'Set4'{set41=[],set42=[],set43=[]}),
+ roundtrip('Set4',
+ #'Set4'{set41=[#'SetIn'{boolIn=true,intIn=25}],
+ set42=asn1_DEFAULT,set43=asn1_DEFAULT},
+ #'Set4'{set41=[#'SetIn'{boolIn=true,intIn=25}],
+ set42=[],set43=[]}),
+ roundtrip('Set4',
+ #'Set4'{set41=[#'SetIn'{boolIn=true,intIn=25},
+ #'SetIn'{boolIn=false,intIn=125},
+ #'SetIn'{boolIn=false,intIn=225}],
+ set42=asn1_DEFAULT,set43=asn1_DEFAULT},
+ #'Set4'{set41=[#'SetIn'{boolIn=true,intIn=25},
+ #'SetIn'{boolIn=false,intIn=125},
+ #'SetIn'{boolIn=false,intIn=225}],
+ set42=[],set43=[]}),
+ roundtrip('Set4',
+ #'Set4'{set41=asn1_DEFAULT,
+ set42=[#'SetIn'{boolIn=true,intIn=25}],
+ set43=asn1_DEFAULT},
+ #'Set4'{set41=[],
+ set42=[#'SetIn'{boolIn=true,intIn=25}],
+ set43=[]}),
+ roundtrip('Set4',
+ #'Set4'{set41=asn1_DEFAULT,
+ set42=[#'SetIn'{boolIn=true,intIn=25},
+ #'SetIn'{boolIn=false,intIn=125},
+ #'SetIn'{boolIn=false,intIn=225}],
+ set43=asn1_DEFAULT},
+ #'Set4'{set41=[],
+ set42=[#'SetIn'{boolIn=true,intIn=25},
+ #'SetIn'{boolIn=false,intIn=125},
+ #'SetIn'{boolIn=false,intIn=225}],
+ set43=[]}),
+ roundtrip('Set4',
+ #'Set4'{set41=asn1_DEFAULT,set42=asn1_DEFAULT,
+ set43=[#'SetIn'{boolIn=true,intIn=25}]},
+ #'Set4'{set41=[],set42=[],
+ set43=[#'SetIn'{boolIn=true,intIn=25}]}),
+ roundtrip('Set4',
+ #'Set4'{set41=asn1_DEFAULT,set42=asn1_DEFAULT,
+ set43=[#'SetIn'{boolIn=true,intIn=25},
+ #'SetIn'{boolIn=false,intIn=125},
+ #'SetIn'{boolIn=false,intIn=225}]},
+ #'Set4'{set41=[],set42=[],
+ set43=[#'SetIn'{boolIn=true,intIn=25},
+ #'SetIn'{boolIn=false,intIn=125},
+ #'SetIn'{boolIn=false,intIn=225}]}),
+
+ roundtrip('SetOs', ["First","Second","Third"]),
+ roundtrip('SetOsImp', ["First","Second","Third"]),
+ roundtrip('SetOsExp', ["First","Second","Third"]),
+ roundtrip('SetEmp', #'SetEmp'{set1=[#'Empty'{}]}),
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SetOf','Set1',#'Set1'{bool1 = true,
- int1 = 17}),
- ?line {ok,{'Set1',true,17,[]}} =
- asn1_wrapper:decode('SetOf','Set1',lists:flatten(Bytes11)),
-
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SetOf','Set1',#'Set1'{bool1 = true,
- int1 = 17,
- set1 = [#'SetIn'{boolIn = true,
- intIn = 25}]}),
- ?line {ok,{'Set1',true,17,[{'SetIn',true,25}]}} =
- asn1_wrapper:decode('SetOf','Set1',lists:flatten(Bytes12)),
-
-
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SetOf','Set1',#'Set1'{bool1 = true,
- int1 = 17,
- set1 = [#'SetIn'{boolIn = true,
- intIn = 25},
- #'SetIn'{boolIn = false,
- intIn = 125},
- #'SetIn'{boolIn = false,
- intIn = 225}]}),
- ?line {ok,{'Set1',true,17,[{'SetIn',true,25},{'SetIn',false,125},{'SetIn',false,225}]}} =
- asn1_wrapper:decode('SetOf','Set1',lists:flatten(Bytes13)),
-
-
-
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SetOf','Set2',#'Set2'{bool2 = true,
- int2 = 17}),
-
- ?line {ok,{'Set2',[],true,17}} =
- asn1_wrapper:decode('SetOf','Set2',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SetOf','Set2',#'Set2'{bool2 = true,
- int2 = 17,
- set2 = [#'SetIn'{boolIn = true,
- intIn = 25}]}),
- ?line {ok,{'Set2',[{'SetIn',true,25}],true,17}} =
- asn1_wrapper:decode('SetOf','Set2',lists:flatten(Bytes22)),
-
-
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('SetOf','Set2',#'Set2'{bool2 = true,
- int2 = 17,
- set2 = [#'SetIn'{boolIn = true,
- intIn = 25},
- #'SetIn'{boolIn = false,
- intIn = 125},
- #'SetIn'{boolIn = false,
- intIn = 225}]}),
- ?line {ok,{'Set2',[{'SetIn',true,25},{'SetIn',false,125},{'SetIn',false,225}],true,17}} =
- asn1_wrapper:decode('SetOf','Set2',lists:flatten(Bytes23)),
-
-
-
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SetOf','Set3',#'Set3'{bool3 = true,
- int3 = 17}),
- ?line {ok,{'Set3',true,[],17}} =
- asn1_wrapper:decode('SetOf','Set3',lists:flatten(Bytes31)),
-
-
- ?line {ok,Bytes32} =
- asn1_wrapper:encode('SetOf','Set3',#'Set3'{bool3 = true,
- int3 = 17,
- set3 = [#'SetIn'{boolIn = true,
- intIn = 25}]}),
- ?line {ok,{'Set3',true,[{'SetIn',true,25}],17}} =
- asn1_wrapper:decode('SetOf','Set3',lists:flatten(Bytes32)),
-
-
- ?line {ok,Bytes33} =
- asn1_wrapper:encode('SetOf','Set3',#'Set3'{bool3 = true,
- int3 = 17,
- set3 = [#'SetIn'{boolIn = true,
- intIn = 25},
- #'SetIn'{boolIn = false,
- intIn = 125},
- #'SetIn'{boolIn = false,
- intIn = 225}]}),
- ?line {ok,{'Set3',true,[{'SetIn',true,25},{'SetIn',false,125},{'SetIn',false,225}],17}} =
- asn1_wrapper:decode('SetOf','Set3',lists:flatten(Bytes33)),
-
-
-
-
-
-
-
- ?line {ok,Bytes41} = asn1_wrapper:encode('SetOf','Set4',#'Set4'{}),
- ?line {ok,{'Set4',[],[],[]}} = asn1_wrapper:decode('SetOf','Set4',lists:flatten(Bytes41)),
-
-
- ?line {ok,Bytes42} =
- asn1_wrapper:encode('SetOf','Set4',#'Set4'{set41 = [#'SetIn'{boolIn = true,
- intIn = 25}]}),
- ?line {ok,{'Set4',[{'SetIn',true,25}],[],[]}} =
- asn1_wrapper:decode('SetOf','Set4',lists:flatten(Bytes42)),
-
-
- ?line {ok,Bytes43} =
- asn1_wrapper:encode('SetOf','Set4',#'Set4'{set41 = [#'SetIn'{boolIn = true,
- intIn = 25},
- #'SetIn'{boolIn = false,
- intIn = 125},
- #'SetIn'{boolIn = false,
- intIn = 225}]}),
- ?line {ok,{'Set4',[{'SetIn',true,25},{'SetIn',false,125},{'SetIn',false,225}],[],[]}} =
- asn1_wrapper:decode('SetOf','Set4',lists:flatten(Bytes43)),
-
-
- ?line {ok,Bytes44} =
- asn1_wrapper:encode('SetOf','Set4',#'Set4'{set42 = [#'SetIn'{boolIn = true,
- intIn = 25}]}),
- ?line {ok,{'Set4',[],[{'SetIn',true,25}],[]}} =
- asn1_wrapper:decode('SetOf','Set4',lists:flatten(Bytes44)),
-
-
- ?line {ok,Bytes45} =
- asn1_wrapper:encode('SetOf','Set4',#'Set4'{set42 = [#'SetIn'{boolIn = true,
- intIn = 25},
- #'SetIn'{boolIn = false,
- intIn = 125},
- #'SetIn'{boolIn = false,
- intIn = 225}]}),
- ?line {ok,{'Set4',[],[{'SetIn',true,25},{'SetIn',false,125},{'SetIn',false,225}],[]}} =
- asn1_wrapper:decode('SetOf','Set4',lists:flatten(Bytes45)),
-
-
- ?line {ok,Bytes46} =
- asn1_wrapper:encode('SetOf','Set4',#'Set4'{set43 = [#'SetIn'{boolIn = true,
- intIn = 25}]}),
- ?line {ok,{'Set4',[],[],[{'SetIn',true,25}]}} =
- asn1_wrapper:decode('SetOf','Set4',lists:flatten(Bytes46)),
-
-
- ?line {ok,Bytes47} =
- asn1_wrapper:encode('SetOf','Set4',#'Set4'{set43 = [#'SetIn'{boolIn = true,
- intIn = 25},
- #'SetIn'{boolIn = false,
- intIn = 125},
- #'SetIn'{boolIn = false,
- intIn = 225}]}),
- ?line {ok,{'Set4',[],[],[{'SetIn',true,25},{'SetIn',false,125},{'SetIn',false,225}]}} =
- asn1_wrapper:decode('SetOf','Set4',lists:flatten(Bytes47)),
-
-
-
-
- ?line {ok,Bytes51} = asn1_wrapper:encode('SetOf','SetOs',["First","Second","Third"]),
- ?line {ok,["First","Second","Third"]} =
- asn1_wrapper:decode('SetOf','SetOs',lists:flatten(Bytes51)),
-
- ?line {ok,Bytes52} = asn1_wrapper:encode('SetOf','SetOsImp',["First","Second","Third"]),
- ?line {ok,["First","Second","Third"]} =
- asn1_wrapper:decode('SetOf','SetOsImp',lists:flatten(Bytes52)),
-
- ?line {ok,Bytes53} = asn1_wrapper:encode('SetOf','SetOsExp',["First","Second","Third"]),
- ?line {ok,["First","Second","Third"]} =
- asn1_wrapper:decode('SetOf','SetOsExp',lists:flatten(Bytes53)),
-
-
-
-
-
-
-
- ?line {ok,Bytes71} = asn1_wrapper:encode('SetOf','SetEmp',#'SetEmp'{set1 = [#'Empty'{}]}),
- ?line {ok,{'SetEmp',[{'Empty'}]}} = asn1_wrapper:decode('SetOf','SetEmp',lists:flatten(Bytes71)),
-
ok.
+roundtrip(T, V) ->
+ roundtrip(T, V, V).
+
+roundtrip(Type, Value, ExpectedValue) ->
+ asn1_test_lib:roundtrip('SetOf', Type, Value, ExpectedValue).
diff --git a/lib/asn1/test/testSetOfCho.erl b/lib/asn1/test/testSetOfCho.erl
index c89bf9596e..09c075e468 100644
--- a/lib/asn1/test/testSetOfCho.erl
+++ b/lib/asn1/test/testSetOfCho.erl
@@ -30,120 +30,46 @@
-record('SetOfChoEmbDef_SETOF',{bool1, int1, set1 = asn1_DEFAULT}).
-record('SetOfChoEmbOpt_SETOF',{bool1, int1, set1 = asn1_NOVALUE}).
+main(_Rules) ->
+ roundtrip('SetChoDef',
+ #'SetChoDef'{bool1=true,int1=17,set1=asn1_DEFAULT},
+ #'SetChoDef'{bool1=true,int1=17,set1=[]}),
+ roundtrip('SetChoDef',
+ #'SetChoDef'{bool1=true,int1=17,set1=[{boolIn,true},{intIn,25}]}),
+ roundtrip('SetChoOpt',
+ #'SetChoOpt'{bool1=true,int1=17,set1=asn1_NOVALUE}),
+ roundtrip('SetChoOpt',
+ #'SetChoOpt'{bool1=true,int1=17,set1=[{boolIn,true},{intIn,25}]}),
+ roundtrip('SetChoEmbDef',
+ #'SetChoEmbDef'{bool1=true,int1=17,set1=asn1_DEFAULT},
+ #'SetChoEmbDef'{bool1=true,int1=17,set1=[]}),
+ roundtrip('SetChoEmbDef',
+ #'SetChoEmbDef'{bool1=true,int1=17,
+ set1=[{boolIn,true},{intIn,25}]}),
+ roundtrip('SetChoEmbOpt',
+ #'SetChoEmbOpt'{bool1=true,int1=17,set1=asn1_NOVALUE}),
+ roundtrip('SetChoEmbOpt',
+ #'SetChoEmbOpt'{bool1=true,int1=17,
+ set1=[{boolIn,true},{intIn,25}]}),
+
+ roundtrip('SetOfChoEmbDef',
+ [#'SetOfChoEmbDef_SETOF'{bool1=true,int1=17,set1=asn1_DEFAULT}],
+ [#'SetOfChoEmbDef_SETOF'{bool1=true,int1=17,set1=[]}]),
+ roundtrip('SetOfChoEmbDef',
+ [#'SetOfChoEmbDef_SETOF'{bool1=true,int1=17,
+ set1=[{boolIn,true},{intIn,25}]}]),
+
+ roundtrip('SetOfChoEmbOpt',
+ [#'SetOfChoEmbOpt_SETOF'{bool1=true,int1=17,set1=asn1_NOVALUE}]),
+ roundtrip('SetOfChoEmbOpt',
+ [#'SetOfChoEmbOpt_SETOF'{bool1=true,int1=17,
+ set1=[{boolIn,true},{intIn,25}]}]),
-main(_Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SetOfCho','SetChoDef',#'SetChoDef'{bool1 = true,
- int1 = 17}),
- ?line {ok,{'SetChoDef',true,17,[]}} =
- asn1_wrapper:decode('SetOfCho','SetChoDef',lists:flatten(Bytes11)),
-
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SetOfCho','SetChoDef',#'SetChoDef'{bool1 = true,
- int1 = 17,
- set1 = [{boolIn,true},
- {intIn,25}]}),
- ?line {ok,{'SetChoDef',true,17,[{boolIn,true},{intIn,25}]}} =
- asn1_wrapper:decode('SetOfCho','SetChoDef',lists:flatten(Bytes12)),
-
-
-
- ?line {ok,Bytes15} =
- asn1_wrapper:encode('SetOfCho','SetChoOpt',#'SetChoOpt'{bool1 = true,
- int1 = 17}),
- ?line {ok,{'SetChoOpt',true,17,asn1_NOVALUE}} =
- asn1_wrapper:decode('SetOfCho','SetChoOpt',lists:flatten(Bytes15)),
-
-
- ?line {ok,Bytes16} =
- asn1_wrapper:encode('SetOfCho','SetChoOpt',#'SetChoOpt'{bool1 = true,
- int1 = 17,
- set1 = [{boolIn,true},
- {intIn,25}]}),
- ?line {ok,{'SetChoOpt',true,17,[{boolIn,true},{intIn,25}]}} =
- asn1_wrapper:decode('SetOfCho','SetChoOpt',lists:flatten(Bytes16)),
-
-
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SetOfCho','SetChoEmbDef',#'SetChoEmbDef'{bool1 = true,
- int1 = 17}),
- ?line {ok,{'SetChoEmbDef',true,17,[]}} =
- asn1_wrapper:decode('SetOfCho','SetChoEmbDef',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SetOfCho','SetChoEmbDef',#'SetChoEmbDef'{bool1 = true,
- int1 = 17,
- set1 = [{boolIn,true},
- {intIn,25}]}),
- ?line {ok,{'SetChoEmbDef',true,17,[{boolIn,true},{intIn,25}]}} =
- asn1_wrapper:decode('SetOfCho','SetChoEmbDef',lists:flatten(Bytes22)),
-
-
-
- ?line {ok,Bytes25} =
- asn1_wrapper:encode('SetOfCho','SetChoEmbOpt',#'SetChoEmbOpt'{bool1 = true,
- int1 = 17}),
- ?line {ok,{'SetChoEmbOpt',true,17,asn1_NOVALUE}} =
- asn1_wrapper:decode('SetOfCho','SetChoEmbOpt',lists:flatten(Bytes25)),
-
-
- ?line {ok,Bytes26} =
- asn1_wrapper:encode('SetOfCho','SetChoEmbOpt',#'SetChoEmbOpt'{bool1 = true,
- int1 = 17,
- set1 = [{boolIn,true},
- {intIn,25}]}),
- ?line {ok,{'SetChoEmbOpt',true,17,[{boolIn,true},{intIn,25}]}} =
- asn1_wrapper:decode('SetOfCho','SetChoEmbOpt',lists:flatten(Bytes26)),
-
-
-
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SetOfCho','SetOfChoEmbDef',[#'SetOfChoEmbDef_SETOF'{bool1 = true,
- int1 = 17}]),
- ?line {ok,[{'SetOfChoEmbDef_SETOF',true,17,[]}]} =
- asn1_wrapper:decode('SetOfCho','SetOfChoEmbDef',lists:flatten(Bytes31)),
-
-
- ?line {ok,Bytes32} =
- asn1_wrapper:encode('SetOfCho','SetOfChoEmbDef',
- [#'SetOfChoEmbDef_SETOF'{bool1 = true,
- int1 = 17,
- set1 = [{boolIn,true},
- {intIn,25}]}]),
- ?line {ok,[{'SetOfChoEmbDef_SETOF',true,17,[{boolIn,true},{intIn,25}]}]} =
- asn1_wrapper:decode('SetOfCho','SetOfChoEmbDef',lists:flatten(Bytes32)),
-
-
-
- ?line {ok,Bytes35} =
- asn1_wrapper:encode('SetOfCho','SetOfChoEmbOpt',[#'SetOfChoEmbOpt_SETOF'{bool1 = true,
- int1 = 17}]),
- ?line {ok,[{'SetOfChoEmbOpt_SETOF',true,17,asn1_NOVALUE}]} =
- asn1_wrapper:decode('SetOfCho','SetOfChoEmbOpt',lists:flatten(Bytes35)),
-
-
- ?line {ok,Bytes36} =
- asn1_wrapper:encode('SetOfCho','SetOfChoEmbOpt',
- [#'SetOfChoEmbOpt_SETOF'{bool1 = true,
- int1 = 17,
- set1 = [{boolIn,true},
- {intIn,25}]}]),
- ?line {ok,[{'SetOfChoEmbOpt_SETOF',true,17,[{boolIn,true},{intIn,25}]}]} =
- asn1_wrapper:decode('SetOfCho','SetOfChoEmbOpt',lists:flatten(Bytes36)),
-
-
-
-
ok.
+roundtrip(T, V) ->
+ roundtrip(T, V, V).
+roundtrip(Type, Value, ExpectedValue) ->
+ asn1_test_lib:roundtrip('SetOfCho', Type, Value, ExpectedValue).
diff --git a/lib/asn1/test/testSetOfExternal.erl b/lib/asn1/test/testSetOfExternal.erl
index 6b280a2595..a380ba5ac1 100644
--- a/lib/asn1/test/testSetOfExternal.erl
+++ b/lib/asn1/test/testSetOfExternal.erl
@@ -18,8 +18,6 @@
%%
%%
-module(testSetOfExternal).
-
-
-export([main/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -29,133 +27,26 @@
-record('Imp',{os, bool}).
-record('Exp',{os, bool}).
-
-
main(_Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SetOfExternal','NTNT',[#'NT'{bool = true, os = "kalle"},
- #'NT'{bool = true, os = "kalle"}]),
- ?line {ok,[{'NT',[107,97,108,108,101],true},{'NT',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','NTNT',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SetOfExternal','ImpNT',[#'NT'{bool = true, os = "kalle"},
- #'NT'{bool = true, os = "kalle"}]),
- ?line {ok,[{'NT',[107,97,108,108,101],true},{'NT',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','ImpNT',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SetOfExternal','ExpNT',[#'NT'{bool = true, os = "kalle"},
- #'NT'{bool = true, os = "kalle"}]),
- ?line {ok,[{'NT',[107,97,108,108,101],true},{'NT',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','ExpNT',lists:flatten(Bytes13)),
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SetOfExternal','NTImp',[#'Imp'{bool = true, os = "kalle"},
- #'Imp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'Imp',[107,97,108,108,101],true},{'Imp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','NTImp',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SetOfExternal','ImpImp',[#'Imp'{bool = true, os = "kalle"},
- #'Imp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'Imp',[107,97,108,108,101],true},{'Imp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','ImpImp',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('SetOfExternal','ExpImp',[#'Imp'{bool = true, os = "kalle"},
- #'Imp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'Imp',[107,97,108,108,101],true},{'Imp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','ExpImp',lists:flatten(Bytes23)),
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SetOfExternal','NTExp',[#'Exp'{bool = true, os = "kalle"},
- #'Exp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'Exp',[107,97,108,108,101],true},{'Exp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','NTExp',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} =
- asn1_wrapper:encode('SetOfExternal','ImpExp',[#'Exp'{bool = true, os = "kalle"},
- #'Exp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'Exp',[107,97,108,108,101],true},{'Exp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','ImpExp',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes33} =
- asn1_wrapper:encode('SetOfExternal','ExpExp',[#'Exp'{bool = true, os = "kalle"},
- #'Exp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'Exp',[107,97,108,108,101],true},{'Exp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','ExpExp',lists:flatten(Bytes33)),
-
-
-
-
-
-
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SetOfExternal','XNTNT',[#'XSetNT'{bool = true, os = "kalle"},
- #'XSetNT'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSetNT',[107,97,108,108,101],true},{'XSetNT',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','XNTNT',lists:flatten(Bytes41)),
-
- ?line {ok,Bytes42} =
- asn1_wrapper:encode('SetOfExternal','XImpNT',[#'XSetNT'{bool = true, os = "kalle"},
- #'XSetNT'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSetNT',[107,97,108,108,101],true},{'XSetNT',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','XImpNT',lists:flatten(Bytes42)),
-
- ?line {ok,Bytes43} =
- asn1_wrapper:encode('SetOfExternal','XExpNT',[#'XSetNT'{bool = true, os = "kalle"},
- #'XSetNT'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSetNT',[107,97,108,108,101],true},{'XSetNT',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','XExpNT',lists:flatten(Bytes43)),
-
-
-
- ?line {ok,Bytes51} =
- asn1_wrapper:encode('SetOfExternal','XNTImp',[#'XSetImp'{bool = true, os = "kalle"},
- #'XSetImp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSetImp',[107,97,108,108,101],true},{'XSetImp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','XNTImp',lists:flatten(Bytes51)),
-
- ?line {ok,Bytes52} =
- asn1_wrapper:encode('SetOfExternal','XImpImp',[#'XSetImp'{bool = true, os = "kalle"},
- #'XSetImp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSetImp',[107,97,108,108,101],true},{'XSetImp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','XImpImp',lists:flatten(Bytes52)),
-
- ?line {ok,Bytes53} =
- asn1_wrapper:encode('SetOfExternal','XExpImp',[#'XSetImp'{bool = true, os = "kalle"},
- #'XSetImp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSetImp',[107,97,108,108,101],true},{'XSetImp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','XExpImp',lists:flatten(Bytes53)),
-
-
-
- ?line {ok,Bytes61} =
- asn1_wrapper:encode('SetOfExternal','XNTExp',[#'XSetExp'{bool = true, os = "kalle"},
- #'XSetExp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSetExp',[107,97,108,108,101],true},{'XSetExp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','XNTExp',lists:flatten(Bytes61)),
-
- ?line {ok,Bytes62} =
- asn1_wrapper:encode('SetOfExternal','XImpExp',[#'XSetExp'{bool = true, os = "kalle"},
- #'XSetExp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSetExp',[107,97,108,108,101],true},{'XSetExp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','XImpExp',lists:flatten(Bytes62)),
-
- ?line {ok,Bytes63} =
- asn1_wrapper:encode('SetOfExternal','XExpExp',[#'XSetExp'{bool = true, os = "kalle"},
- #'XSetExp'{bool = true, os = "kalle"}]),
- ?line {ok,[{'XSetExp',[107,97,108,108,101],true},{'XSetExp',[107,97,108,108,101],true}]} =
- asn1_wrapper:decode('SetOfExternal','XExpExp',lists:flatten(Bytes63)),
-
-
-
-
+ roundtrip('NTNT', [#'NT'{os="kalle",bool=true},#'NT'{os="kalle",bool=true}]),
+ roundtrip('ImpNT', [#'NT'{os="kalle",bool=true},#'NT'{os="kalle",bool=true}]),
+ roundtrip('ExpNT', [#'NT'{os="kalle",bool=true},#'NT'{os="kalle",bool=true}]),
+ roundtrip('NTImp', [#'Imp'{os="kalle",bool=true},#'Imp'{os="kalle",bool=true}]),
+ roundtrip('ImpImp', [#'Imp'{os="kalle",bool=true},#'Imp'{os="kalle",bool=true}]),
+ roundtrip('ExpImp', [#'Imp'{os="kalle",bool=true},#'Imp'{os="kalle",bool=true}]),
+ roundtrip('NTExp', [#'Exp'{os="kalle",bool=true},#'Exp'{os="kalle",bool=true}]),
+ roundtrip('ImpExp', [#'Exp'{os="kalle",bool=true},#'Exp'{os="kalle",bool=true}]),
+ roundtrip('ExpExp', [#'Exp'{os="kalle",bool=true},#'Exp'{os="kalle",bool=true}]),
+ roundtrip('XNTNT', [#'XSetNT'{os="kalle",bool=true},#'XSetNT'{os="kalle",bool=true}]),
+ roundtrip('XImpNT', [#'XSetNT'{os="kalle",bool=true},#'XSetNT'{os="kalle",bool=true}]),
+ roundtrip('XExpNT', [#'XSetNT'{os="kalle",bool=true},#'XSetNT'{os="kalle",bool=true}]),
+ roundtrip('XNTImp', [#'XSetImp'{os="kalle",bool=true},#'XSetImp'{os="kalle",bool=true}]),
+ roundtrip('XImpImp', [#'XSetImp'{os="kalle",bool=true},#'XSetImp'{os="kalle",bool=true}]),
+ roundtrip('XExpImp', [#'XSetImp'{os="kalle",bool=true},#'XSetImp'{os="kalle",bool=true}]),
+ roundtrip('XNTExp', [#'XSetExp'{os="kalle",bool=true},#'XSetExp'{os="kalle",bool=true}]),
+ roundtrip('XImpExp', [#'XSetExp'{os="kalle",bool=true},#'XSetExp'{os="kalle",bool=true}]),
+ roundtrip('XExpExp', [#'XSetExp'{os="kalle",bool=true},#'XSetExp'{os="kalle",bool=true}]),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SetOfExternal', T, V).
diff --git a/lib/asn1/test/testSetOfTag.erl b/lib/asn1/test/testSetOfTag.erl
index 2c7a2f5473..81bc467abb 100644
--- a/lib/asn1/test/testSetOfTag.erl
+++ b/lib/asn1/test/testSetOfTag.erl
@@ -18,14 +18,11 @@
%%
%%
-module(testSetOfTag).
-
-
-export([main/1]).
-include_lib("test_server/include/test_server.hrl").
-include("External.hrl").
-
-record('SetTagNt',{nt}).
-record('SetTagNtI',{imp}).
-record('SetTagNtE',{exp}).
@@ -44,148 +41,44 @@
-record('Imp',{os, bool}).
-record('Exp',{os, bool}).
-
-
main(_Rules) ->
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SetOfTag','SetTagNt',
- #'SetTagNt'{nt = [#'NT'{bool = true, os = "kalle"},
- #'NT'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagNt',
- [{'NT',[107,97,108,108,101],true},{'NT',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagNt',lists:flatten(Bytes11)),
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SetOfTag','SetTagNtI',
- #'SetTagNtI'{imp = [#'Imp'{bool = true, os = "kalle"},
- #'Imp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagNtI',
- [{'Imp',[107,97,108,108,101],true},{'Imp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagNtI',lists:flatten(Bytes12)),
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SetOfTag','SetTagNtE',
- #'SetTagNtE'{exp = [#'Exp'{bool = true, os = "kalle"},
- #'Exp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagNtE',
- [{'Exp',[107,97,108,108,101],true},{'Exp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagNtE',lists:flatten(Bytes13)),
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SetOfTag','SetTagI',
- #'SetTagI'{nt = [#'NT'{bool = true, os = "kalle"},
- #'NT'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagI',
- [{'NT',[107,97,108,108,101],true},{'NT',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagI',lists:flatten(Bytes21)),
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SetOfTag','SetTagII',
- #'SetTagII'{imp = [#'Imp'{bool = true, os = "kalle"},
- #'Imp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagII',
- [{'Imp',[107,97,108,108,101],true},{'Imp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagII',lists:flatten(Bytes22)),
-
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('SetOfTag','SetTagIE',
- #'SetTagIE'{exp = [#'Exp'{bool = true, os = "kalle"},
- #'Exp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagIE',
- [{'Exp',[107,97,108,108,101],true},{'Exp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagIE',lists:flatten(Bytes23)),
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SetOfTag','SetTagE',
- #'SetTagE'{nt = [#'NT'{bool = true, os = "kalle"},
- #'NT'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagE',
- [{'NT',[107,97,108,108,101],true},{'NT',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagE',lists:flatten(Bytes31)),
-
- ?line {ok,Bytes32} =
- asn1_wrapper:encode('SetOfTag','SetTagEI',
- #'SetTagEI'{imp = [#'Imp'{bool = true, os = "kalle"},
- #'Imp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagEI',
- [{'Imp',[107,97,108,108,101],true},{'Imp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagEI',lists:flatten(Bytes32)),
-
- ?line {ok,Bytes33} =
- asn1_wrapper:encode('SetOfTag','SetTagEE',
- #'SetTagEE'{exp = [#'Exp'{bool = true, os = "kalle"},
- #'Exp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagEE',
- [{'Exp',[107,97,108,108,101],true},{'Exp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagEE',lists:flatten(Bytes33)),
-
-
-
-
-
-
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SetOfTag','SetTagXNt',
- #'SetTagXNt'{xnt = [#'XSetNT'{bool = true, os = "kalle"},
- #'XSetNT'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagXNt',
- [{'XSetNT',[107,97,108,108,101],true},{'XSetNT',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagXNt',lists:flatten(Bytes41)),
-
- ?line {ok,Bytes42} =
- asn1_wrapper:encode('SetOfTag','SetTagXI',
- #'SetTagXI'{ximp = [#'XSetImp'{bool = true, os = "kalle"},
- #'XSetImp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagXI',
- [{'XSetImp',[107,97,108,108,101],true},{'XSetImp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagXI',lists:flatten(Bytes42)),
-
- ?line {ok,Bytes43} =
- asn1_wrapper:encode('SetOfTag','SetTagXE',
- #'SetTagXE'{xexp = [#'XSetExp'{bool = true, os = "kalle"},
- #'XSetExp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagXE',
- [{'XSetExp',[107,97,108,108,101],true},{'XSetExp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagXE',lists:flatten(Bytes43)),
-
-
-
-
-
- ?line {ok,Bytes51} =
- asn1_wrapper:encode('SetOfTag','SetTagImpX',
- #'SetTagImpX'{xnt = [#'XSetNT'{bool = true, os = "kalle"},
- #'XSetNT'{bool = true, os = "kalle"}],
- ximp = [#'XSetImp'{bool = true, os = "kalle"},
- #'XSetImp'{bool = true, os = "kalle"}],
- xexp = [#'XSetExp'{bool = true, os = "kalle"},
- #'XSetExp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagImpX',
- [{'XSetNT',[107,97,108,108,101],true},{'XSetNT',[107,97,108,108,101],true}],
- [{'XSetImp',[107,97,108,108,101],true},{'XSetImp',[107,97,108,108,101],true}],
- [{'XSetExp',[107,97,108,108,101],true},{'XSetExp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagImpX',lists:flatten(Bytes51)),
-
-
-
- ?line {ok,Bytes52} =
- asn1_wrapper:encode('SetOfTag','SetTagExpX',
- #'SetTagExpX'{xnt = [#'XSetNT'{bool = true, os = "kalle"},
- #'XSetNT'{bool = true, os = "kalle"}],
- ximp = [#'XSetImp'{bool = true, os = "kalle"},
- #'XSetImp'{bool = true, os = "kalle"}],
- xexp = [#'XSetExp'{bool = true, os = "kalle"},
- #'XSetExp'{bool = true, os = "kalle"}]}),
- ?line {ok,{'SetTagExpX',
- [{'XSetNT',[107,97,108,108,101],true},{'XSetNT',[107,97,108,108,101],true}],
- [{'XSetImp',[107,97,108,108,101],true},{'XSetImp',[107,97,108,108,101],true}],
- [{'XSetExp',[107,97,108,108,101],true},{'XSetExp',[107,97,108,108,101],true}]}} =
- asn1_wrapper:decode('SetOfTag','SetTagExpX',lists:flatten(Bytes52)),
-
+ roundtrip('SetTagNt', #'SetTagNt'{nt=[#'NT'{os="kalle",bool=true},
+ #'NT'{os="kalle",bool=true}]}),
+ roundtrip('SetTagNtI', #'SetTagNtI'{imp=[#'Imp'{os="kalle",bool=true},
+ #'Imp'{os="kalle",bool=true}]}),
+ roundtrip('SetTagNtE', #'SetTagNtE'{exp=[#'Exp'{os="kalle",bool=true},
+ #'Exp'{os="kalle",bool=true}]}),
+ roundtrip('SetTagI', #'SetTagI'{nt=[#'NT'{os="kalle",bool=true},
+ #'NT'{os="kalle",bool=true}]}),
+ roundtrip('SetTagII', #'SetTagII'{imp=[#'Imp'{os="kalle",bool=true},
+ #'Imp'{os="kalle",bool=true}]}),
+ roundtrip('SetTagIE', #'SetTagIE'{exp=[#'Exp'{os="kalle",bool=true},
+ #'Exp'{os="kalle",bool=true}]}),
+ roundtrip('SetTagE', #'SetTagE'{nt=[#'NT'{os="kalle",bool=true},
+ #'NT'{os="kalle",bool=true}]}),
+ roundtrip('SetTagEI', #'SetTagEI'{imp=[#'Imp'{os="kalle",bool=true},
+ #'Imp'{os="kalle",bool=true}]}),
+ roundtrip('SetTagEE', #'SetTagEE'{exp=[#'Exp'{os="kalle",bool=true},
+ #'Exp'{os="kalle",bool=true}]}),
+ roundtrip('SetTagXNt', #'SetTagXNt'{xnt=[#'XSetNT'{os="kalle",bool=true},
+ #'XSetNT'{os="kalle",bool=true}]}),
+ roundtrip('SetTagXI', #'SetTagXI'{ximp=[#'XSetImp'{os="kalle",bool=true},
+ #'XSetImp'{os="kalle",bool=true}]}),
+ roundtrip('SetTagXE', #'SetTagXE'{xexp=[#'XSetExp'{os="kalle",bool=true},
+ #'XSetExp'{os="kalle",bool=true}]}),
+ roundtrip('SetTagImpX', #'SetTagImpX'{xnt=[#'XSetNT'{os="kalle",bool=true},
+ #'XSetNT'{os="kalle",bool=true}],
+ ximp=[#'XSetImp'{os="kalle",bool=true},
+ #'XSetImp'{os="kalle",bool=true}],
+ xexp=[#'XSetExp'{os="kalle",bool=true},
+ #'XSetExp'{os="kalle",bool=true}]}),
+ roundtrip('SetTagExpX', #'SetTagExpX'{xnt=[#'XSetNT'{os="kalle",bool=true},
+ #'XSetNT'{os="kalle",bool=true}],
+ ximp=[#'XSetImp'{os="kalle",bool=true},
+ #'XSetImp'{os="kalle",bool=true}],
+ xexp=[#'XSetExp'{os="kalle",bool=true},
+ #'XSetExp'{os="kalle",bool=true}]}),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SetOfTag', T, V).
diff --git a/lib/asn1/test/testSetOptional.erl b/lib/asn1/test/testSetOptional.erl
index bb43ff0a96..eb095fd480 100644
--- a/lib/asn1/test/testSetOptional.erl
+++ b/lib/asn1/test/testSetOptional.erl
@@ -93,6 +93,4 @@ ticket_7533(_) ->
ok.
roundtrip(Type, Value) ->
- {ok,Encoded} = 'SetOptional':encode(Type, Value),
- {ok,Value} = 'SetOptional':decode(Type, Encoded),
- ok.
+ asn1_test_lib:roundtrip('SetOptional', Type, Value).
diff --git a/lib/asn1/test/testSetPrim.erl b/lib/asn1/test/testSetPrim.erl
index 3234b65135..f417f343a7 100644
--- a/lib/asn1/test/testSetPrim.erl
+++ b/lib/asn1/test/testSetPrim.erl
@@ -27,59 +27,17 @@
-record('Empty',{}).
main(_Rules) ->
-
-
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SetPrim','Set',#'Set'{bool = true,
- boolCon = true,
- boolPri = true,
- boolApp = true,
- boolExpCon = true,
- boolExpPri = true,
- boolExpApp = true}),
- ?line {ok,{'Set',true,true,true,true,true,true,true}} =
- asn1_wrapper:decode('SetPrim','Set',lists:flatten(Bytes11)),
-
-
-
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SetPrim','Set',#'Set'{bool = false,
- boolCon = false,
- boolPri = false,
- boolApp = false,
- boolExpCon = false,
- boolExpPri = false,
- boolExpApp = false}),
- ?line {ok,{'Set',false,false,false,false,false,false,false}} =
- asn1_wrapper:decode('SetPrim','Set',lists:flatten(Bytes12)),
-
-
-
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SetPrim','Set',#'Set'{bool = false,
- boolCon = true,
- boolPri = false,
- boolApp = true,
- boolExpCon = false,
- boolExpPri = true,
- boolExpApp = false}),
- ?line {ok,{'Set',false,true,false,true,false,true,false}} =
- asn1_wrapper:decode('SetPrim','Set',lists:flatten(Bytes13)),
-
-
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SetPrim','Empty',#'Empty'{}),
- ?line {ok,{'Empty'}} =
- asn1_wrapper:decode('SetPrim','Empty',lists:flatten(Bytes21)),
-
-
-
+ roundtrip('Set',
+ #'Set'{bool=true,boolCon=true,boolPri=true,boolApp=true,
+ boolExpCon=true,boolExpPri=true,boolExpApp=true}),
+ roundtrip('Set',
+ #'Set'{bool=false,boolCon=false,boolPri=false,boolApp=false,
+ boolExpCon=false,boolExpPri=false,boolExpApp=false}),
+ roundtrip('Set',
+ #'Set'{bool=false,boolCon=true,boolPri=false,boolApp=true,
+ boolExpCon=false,boolExpPri=true,boolExpApp=false}),
+ roundtrip('Empty', #'Empty'{}),
ok.
-
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SetPrim', T, V).
diff --git a/lib/asn1/test/testSetTag.erl b/lib/asn1/test/testSetTag.erl
index 8b9364d603..5863a149b9 100644
--- a/lib/asn1/test/testSetTag.erl
+++ b/lib/asn1/test/testSetTag.erl
@@ -18,7 +18,6 @@
%%
%%
-module(testSetTag).
-
-export([main/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -35,69 +34,25 @@
-record('Exp',{os, bool}).
main(_Rules) ->
-
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SetTag','SetTag',#'SetTag'{nt = #'NT'{bool = true, os = "kalle"},
- imp = #'Imp'{bool = true, os = "kalle"},
- exp = #'Exp'{bool = true, os = "kalle"}}),
- ?line {ok,{'SetTag',{'NT',"kalle",true},{'Imp',"kalle",true},{'Exp',"kalle",true}}} =
- asn1_wrapper:decode('SetTag','SetTag',lists:flatten(Bytes11)),
-
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SetTag','SetTagImp',#'SetTagImp'{nt = #'NT'{bool = true, os = "kalle"},
- imp = #'Imp'{bool = true, os = "kalle"},
- exp = #'Exp'{bool = true, os = "kalle"}}),
- ?line {ok,{'SetTagImp',{'NT',"kalle",true},{'Imp',"kalle",true},{'Exp',"kalle",true}}} =
- asn1_wrapper:decode('SetTag','SetTagImp',lists:flatten(Bytes12)),
-
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SetTag','SetTagExp',#'SetTagExp'{nt = #'NT'{bool = true, os = "kalle"},
- imp = #'Imp'{bool = true, os = "kalle"},
- exp = #'Exp'{bool = true, os = "kalle"}}),
- ?line {ok,{'SetTagExp',{'NT',"kalle",true},{'Imp',"kalle",true},{'Exp',"kalle",true}}} =
- asn1_wrapper:decode('SetTag','SetTagExp',lists:flatten(Bytes13)),
-
-
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SetTag','SetTagX',
- #'SetTagX'{xnt = #'XSetNT'{bool = true, os = "kalle"},
- ximp = #'XSetImp'{bool = true, os = "kalle"},
- xexp = #'XSetExp'{bool = true, os = "kalle"}}),
- ?line {ok,{'SetTagX',{'XSetNT',"kalle",true},
- {'XSetImp',"kalle",true},
- {'XSetExp',"kalle",true}}} =
- asn1_wrapper:decode('SetTag','SetTagX',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SetTag','SetTagImpX',
- #'SetTagImpX'{xnt = #'XSetNT'{bool = true, os = "kalle"},
- ximp = #'XSetImp'{bool = true, os = "kalle"},
- xexp = #'XSetExp'{bool = true, os = "kalle"}}),
- ?line {ok,{'SetTagImpX',{'XSetNT',"kalle",true},
- {'XSetImp',"kalle",true},
- {'XSetExp',"kalle",true}}} =
- asn1_wrapper:decode('SetTag','SetTagImpX',lists:flatten(Bytes22)),
-
-
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('SetTag','SetTagExpX',
- #'SetTagExpX'{xnt = #'XSetNT'{bool = true, os = "kalle"},
- ximp = #'XSetImp'{bool = true, os = "kalle"},
- xexp = #'XSetExp'{bool = true, os = "kalle"}}),
- ?line {ok,{'SetTagExpX',{'XSetNT',"kalle",true},
- {'XSetImp',"kalle",true},
- {'XSetExp',"kalle",true}}} =
- asn1_wrapper:decode('SetTag','SetTagExpX',lists:flatten(Bytes23)),
-
-
-
-
-
+ roundtrip('SetTag', #'SetTag'{nt=#'NT'{os="kalle",bool=true},
+ imp=#'Imp'{os="kalle",bool=true},
+ exp=#'Exp'{os="kalle",bool=true}}),
+ roundtrip('SetTagImp', #'SetTagImp'{nt=#'NT'{os="kalle",bool=true},
+ imp=#'Imp'{os="kalle",bool=true},
+ exp=#'Exp'{os="kalle",bool=true}}),
+ roundtrip('SetTagExp', #'SetTagExp'{nt=#'NT'{os="kalle",bool=true},
+ imp=#'Imp'{os="kalle",bool=true},
+ exp=#'Exp'{os="kalle",bool=true}}),
+ roundtrip('SetTagX', #'SetTagX'{xnt=#'XSetNT'{os="kalle",bool=true},
+ ximp=#'XSetImp'{os="kalle",bool=true},
+ xexp=#'XSetExp'{os="kalle",bool=true}}),
+ roundtrip('SetTagImpX', #'SetTagImpX'{xnt=#'XSetNT'{os="kalle",bool=true},
+ ximp=#'XSetImp'{os="kalle",bool=true},
+ xexp=#'XSetExp'{os="kalle",bool=true}}),
+ roundtrip('SetTagExpX', #'SetTagExpX'{xnt=#'XSetNT'{os="kalle",bool=true},
+ ximp=#'XSetImp'{os="kalle",bool=true},
+ xexp=#'XSetExp'{os="kalle",bool=true}}),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SetTag', T, V).
diff --git a/lib/asn1/test/testSetTypeRefCho.erl b/lib/asn1/test/testSetTypeRefCho.erl
index a0989926c7..8d62f45bfa 100644
--- a/lib/asn1/test/testSetTypeRefCho.erl
+++ b/lib/asn1/test/testSetTypeRefCho.erl
@@ -28,17 +28,12 @@
main(_Rules) ->
-
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SetTypeRefCho','SetTRcho',
- #'SetTRcho'{'setCho' = {choOs,"A string 1"},
- 'setChoE' = {choOs,"A string 3"},
- 'setCho-E' = {choOs,"A string 7"},
- 'setChoE-E' = {choOs,"A string 9"}}),
- ?line {ok,{'SetTRcho',{choOs,"A string 1"},{choOs,"A string 3"},{choOs,"A string 7"},{choOs,"A string 9"}}} =
- asn1_wrapper:decode('SetTypeRefCho','SetTRcho',lists:flatten(Bytes11)),
-
-
-
+ roundtrip('SetTRcho',
+ #'SetTRcho'{'setCho' = {choOs,"A string 1"},
+ 'setChoE' = {choOs,"A string 3"},
+ 'setCho-E' = {choOs,"A string 7"},
+ 'setChoE-E' = {choOs,"A string 9"}}),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SetTypeRefCho', T, V).
diff --git a/lib/asn1/test/testSetTypeRefPrim.erl b/lib/asn1/test/testSetTypeRefPrim.erl
index 9c7fbd803e..cc2e157e68 100644
--- a/lib/asn1/test/testSetTypeRefPrim.erl
+++ b/lib/asn1/test/testSetTypeRefPrim.erl
@@ -27,21 +27,17 @@
main(_Rules) ->
-
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SetTypeRefPrim','SetTR',#'SetTR'{'octStr' = "A string 1",
- 'octStrI' = "A string 2",
- 'octStrE' = "A string 3",
- 'octStr-I' = "A string 4",
- 'octStrI-I' = "A string 5",
- 'octStrE-I' = "A string 6",
- 'octStr-E' = "A string 7",
- 'octStrI-E' = "A string 8",
- 'octStrE-E' = "A string 9"}),
- ?line {ok,{'SetTR',"A string 1","A string 2","A string 3","A string 4","A string 5","A string 6","A string 7","A string 8","A string 9"}} =
- asn1_wrapper:decode('SetTypeRefPrim','SetTR',lists:flatten(Bytes11)),
-
-
-
+ roundtrip('SetTR',
+ #'SetTR'{'octStr' = "A string 1",
+ 'octStrI' = "A string 2",
+ 'octStrE' = "A string 3",
+ 'octStr-I' = "A string 4",
+ 'octStrI-I' = "A string 5",
+ 'octStrE-I' = "A string 6",
+ 'octStr-E' = "A string 7",
+ 'octStrI-E' = "A string 8",
+ 'octStrE-E' = "A string 9"}),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SetTypeRefPrim', T, V).
diff --git a/lib/asn1/test/testSetTypeRefSeq.erl b/lib/asn1/test/testSetTypeRefSeq.erl
index a3ef4b188d..17af5c2922 100644
--- a/lib/asn1/test/testSetTypeRefSeq.erl
+++ b/lib/asn1/test/testSetTypeRefSeq.erl
@@ -28,12 +28,8 @@
-record('SetSeqImp',{seqInt, seqOs}).
-record('SetSeqExp',{seqInt, seqOs}).
-
-
main(_Rules) ->
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SetTypeRefSeq','SetTRseq',
+ roundtrip('SetTRseq',
#'SetTRseq'{'setSeq' = #'SetSeq'{seqOs = "A1",
seqInt = 2},
'setSeqI' = #'SetSeq'{seqOs = "A2",
@@ -52,15 +48,7 @@ main(_Rules) ->
seqInt = 2},
'setSeqE-E' = #'SetSeqExp'{seqOs = "A9",
seqInt = 2}}),
- ?line {ok,{'SetTRseq',{'SetSeq',2,"A1"},
- {'SetSeq',2,"A2"},
- {'SetSeq',2,"A3"},
- {'SetSeqImp',2,"A4"},
- {'SetSeqImp',2,"A5"},
- {'SetSeqImp',2,"A6"},
- {'SetSeqExp',2,"A7"},
- {'SetSeqExp',2,"A8"},
- {'SetSeqExp',2,"A9"}}} =
- asn1_wrapper:decode('SetTypeRefSeq','SetTRseq',lists:flatten(Bytes41)),
-
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SetTypeRefSeq', T, V).
diff --git a/lib/asn1/test/testSetTypeRefSet.erl b/lib/asn1/test/testSetTypeRefSet.erl
index ce77316ef8..8786e0fb4d 100644
--- a/lib/asn1/test/testSetTypeRefSet.erl
+++ b/lib/asn1/test/testSetTypeRefSet.erl
@@ -46,131 +46,42 @@
main(_Rules) ->
-
-
- ?line {ok,Bytes11} =
- asn1_wrapper:encode('SetTypeRefSet','Set1',#'Set1'{bool1 = true,
- int1 = 15,
- set1 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'Set1',true,15,{'SetIn',true,66}}} =
- asn1_wrapper:decode('SetTypeRefSet','Set1',lists:flatten(Bytes11)),
-
-
-
- ?line {ok,Bytes12} =
- asn1_wrapper:encode('SetTypeRefSet','Set2',#'Set2'{set2 = #'SetIn'{boolIn = true,
- intIn = 66},
- bool2 = true,
- int2 = 15}),
- ?line {ok,{'Set2',{'SetIn',true,66},true,15}} =
- asn1_wrapper:decode('SetTypeRefSet','Set2',lists:flatten(Bytes12)),
-
-
- ?line {ok,Bytes13} =
- asn1_wrapper:encode('SetTypeRefSet','Set3',#'Set3'{bool3 = true,
- set3 = #'SetIn'{boolIn = true,
- intIn = 66},
- int3 = 15}),
- ?line {ok,{'Set3',true,{'SetIn',true,66},15}} =
- asn1_wrapper:decode('SetTypeRefSet','Set3',lists:flatten(Bytes13)),
-
-
-
- ?line {ok,Bytes14} =
- asn1_wrapper:encode('SetTypeRefSet','Set4',#'Set4'{set41 = #'SetIn'{boolIn = true,
- intIn = 66},
- set42 = #'SetIn'{boolIn = true,
- intIn = 66},
- set43 = #'SetIn'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'Set4',{'SetIn',true,66},{'SetIn',true,66},{'SetIn',true,66}}} =
- asn1_wrapper:decode('SetTypeRefSet','Set4',lists:flatten(Bytes14)),
-
-
-
-
-
-
-
-
- ?line {ok,Bytes21} =
- asn1_wrapper:encode('SetTypeRefSet','SetS1',#'SetS1'{boolS1 = true,
- intS1 = 15,
- setS1 = #'SetS1_setS1'{boolIn = true,
- intIn = 66}}),
- ?line {ok,{'SetS1',true,15,{'SetS1_setS1',true,66}}} =
- asn1_wrapper:decode('SetTypeRefSet','SetS1',lists:flatten(Bytes21)),
-
-
- ?line {ok,Bytes22} =
- asn1_wrapper:encode('SetTypeRefSet','SetS2',#'SetS2'{setS2 = #'SetS2_setS2'{boolIn = true,
- intIn = 66},
- boolS2 = true,
- intS2 = 15}),
- ?line {ok,{'SetS2',{'SetS2_setS2',true,66},true,15}} =
- asn1_wrapper:decode('SetTypeRefSet','SetS2',lists:flatten(Bytes22)),
-
-
-
- ?line {ok,Bytes23} =
- asn1_wrapper:encode('SetTypeRefSet','SetS3',#'SetS3'{boolS3 = true,
- setS3 = #'SetS3_setS3'{boolIn = true,
- intIn = 66},
- intS3 = 15}),
- ?line {ok,{'SetS3',true,{'SetS3_setS3',true,66},15}} =
- asn1_wrapper:decode('SetTypeRefSet','SetS3',lists:flatten(Bytes23)),
-
-
-
-
-
-
- ?line {ok,Bytes31} =
- asn1_wrapper:encode('SetTypeRefSet','SetSTag',#'SetSTag'{setS1 = #'SetSTag_setS1'{b1 = true,
- i1 = 11},
- setS2 = #'SetSTag_setS2'{b2 = true,
- i2 = 22},
- setS3 = #'SetSTag_setS3'{b3 = true,
- i3 = 33}}),
- ?line {ok,{'SetSTag',{'SetSTag_setS1',true,11},
- {'SetSTag_setS2',true,22},
- {'SetSTag_setS3',true,33}}} =
- asn1_wrapper:decode('SetTypeRefSet','SetSTag',lists:flatten(Bytes31)),
-
-
-
-
-
- ?line {ok,Bytes41} =
- asn1_wrapper:encode('SetTypeRefSet','SetTRset',
- #'SetTRset'{'setSet' = #'SetSet'{setOs = "A1",
- setInt = 2},
- 'setSetI' = #'SetSet'{setOs = "A2",
- setInt = 2},
- 'setSetE' = #'SetSet'{setOs = "A3",
- setInt = 2},
- 'setSet-I' = #'SetSetImp'{setOs = "A4",
- setInt = 2},
- 'setSetI-I' = #'SetSetImp'{setOs = "A5",
- setInt = 2},
- 'setSetE-I' = #'SetSetImp'{setOs = "A6",
- setInt = 2},
- 'setSet-E' = #'SetSetExp'{setOs = "A7",
- setInt = 2},
- 'setSetI-E' = #'SetSetExp'{setOs = "A8",
- setInt = 2},
- 'setSetE-E' = #'SetSetExp'{setOs = "A9",
- setInt = 2}}),
- ?line {ok,{'SetTRset',{'SetSet',2,"A1"},
- {'SetSet',2,"A2"},
- {'SetSet',2,"A3"},
- {'SetSetImp',2,"A4"},
- {'SetSetImp',2,"A5"},
- {'SetSetImp',2,"A6"},
- {'SetSetExp',2,"A7"},
- {'SetSetExp',2,"A8"},
- {'SetSetExp',2,"A9"}}} =
- asn1_wrapper:decode('SetTypeRefSet','SetTRset',lists:flatten(Bytes41)),
+ roundtrip('Set1',
+ #'Set1'{bool1=true,int1=15,set1=#'SetIn'{boolIn=true,intIn=66}}),
+ roundtrip('Set2',
+ #'Set2'{set2=#'SetIn'{boolIn=true,intIn=66},bool2=true,int2=15}),
+ roundtrip('Set3',
+ #'Set3'{bool3=true,set3=#'SetIn'{boolIn=true,intIn=66},int3=15}),
+ roundtrip('Set4',
+ #'Set4'{set41=#'SetIn'{boolIn=true,intIn=66},
+ set42=#'SetIn'{boolIn=true,intIn=66},
+ set43=#'SetIn'{boolIn=true,intIn=66}}),
+ roundtrip('SetS1',
+ #'SetS1'{boolS1=true,intS1=15,
+ setS1=#'SetS1_setS1'{boolIn=true,intIn=66}}),
+ roundtrip('SetS2',
+ #'SetS2'{setS2=#'SetS2_setS2'{boolIn=true,intIn=66},
+ boolS2=true,intS2=15}),
+ roundtrip('SetS3',
+ #'SetS3'{boolS3=true,
+ setS3=#'SetS3_setS3'{boolIn=true,intIn=66},
+ intS3=15}),
+ roundtrip('SetSTag',
+ #'SetSTag'{setS1=#'SetSTag_setS1'{b1=true,i1=11},
+ setS2=#'SetSTag_setS2'{b2=true,i2=22},
+ setS3=#'SetSTag_setS3'{b3=true,i3=33}}),
+ roundtrip('SetTRset',
+ #'SetTRset'{setSet=#'SetSet'{setInt=2,setOs="A1"},
+ setSetI=#'SetSet'{setInt=2,setOs="A2"},
+ setSetE=#'SetSet'{setInt=2,setOs="A3"},
+ 'setSet-I'=#'SetSetImp'{setInt=2,setOs="A4"},
+ 'setSetI-I'=#'SetSetImp'{setInt=2,setOs="A5"},
+ 'setSetE-I'=#'SetSetImp'{setInt=2,setOs="A6"},
+ 'setSet-E'=#'SetSetExp'{setInt=2,setOs="A7"},
+ 'setSetI-E'=#'SetSetExp'{setInt=2,setOs="A8"},
+ 'setSetE-E'=#'SetSetExp'{setInt=2,setOs="A9"}}),
ok.
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SetTypeRefSet', T, V).
diff --git a/lib/asn1/test/testTCAP.erl b/lib/asn1/test/testTCAP.erl
index aba13c94de..17511dc2b7 100644
--- a/lib/asn1/test/testTCAP.erl
+++ b/lib/asn1/test/testTCAP.erl
@@ -40,25 +40,26 @@ compile_asn1config(Config, Options) ->
test(Erule,_Config) ->
% ?line OutDir = ?config(priv_dir,Config),
%% testing OTP-4798, open type encoded with indefinite length
- ?line {ok,_Res} = asn1_wrapper:decode('TCAPMessages-simple','MessageType', val_OTP_4798(Erule)),
+ {ok,_Res} = 'TCAPMessages-simple':decode('MessageType',
+ val_OTP_4798(Erule)),
+
%% testing OTP-4799, absent optional open type
- ?line {ok,_Res2} = asn1_wrapper:decode('TCAPMessages-simple','MessageType',val_OTP_4799(Erule)),
+ {ok,_Res2} = 'TCAPMessages-simple':decode('MessageType',
+ val_OTP_4799(Erule)),
+
%% testing vance shipley's problems. Parameterized object sets.
?line Val3 = 'TCAPPackage_msg':val('PackageType',unidirectional),
- ?line {ok,Bytes3} = asn1_wrapper:encode('TCAPPackage','PackageType',Val3),
- ?line {ok,Res3} = asn1_wrapper:decode('TCAPPackage','PackageType',Bytes3),
+ Res3 = enc_dec('PackageType', Val3),
?line ok = 'TCAPPackage_msg':check_result('PackageType',unidirectional,Res3),
%% ?line io:format("Res3:~n~p~n~n",[Res3]),
?line Val4 = 'TCAPPackage_msg':val('PackageType',abort),
- ?line {ok,Bytes4} = asn1_wrapper:encode('TCAPPackage','PackageType',Val4),
- ?line {ok,Res4} = asn1_wrapper:decode('TCAPPackage','PackageType',Bytes4),
+ Res4 = enc_dec('PackageType', Val4),
?line ok = 'TCAPPackage_msg':check_result('PackageType',abort,Res4),
%% ?line io:format("Res4:~n~p~n~n",[Res4]),
?line Val5 = 'TCAPPackage_msg':val('PackageType',response),
- ?line {ok,Bytes5} = asn1_wrapper:encode('TCAPPackage','PackageType',Val5),
- ?line {ok,Res5} = asn1_wrapper:decode('TCAPPackage','PackageType',Bytes5),
+ Res5 = enc_dec('PackageType', Val5),
?line ok = 'TCAPPackage_msg':check_result('PackageType',response,Res5).
%% ?line io:format("Res5:~n~p~n~n",[Res5]).
@@ -73,21 +74,26 @@ val_OTP_4799(_) ->
<<100,16,73,4,41,182,36,0,108,8,163,6,2,1,29,2,1,27>>.
test_asn1config() ->
- ?line Val = 'TCAPPackage_msg':val('PackageType',queryWithPerm),
- ?line {ok,B} = asn1_wrapper:encode('TCAPPackage','PackageType',Val),
- ?line {ok,ExMsg}='TCAPPackage':decode_PackageType(list_to_binary(B)),
- ?line {_,{_,_,_,{Key,ExVal}}}=ExMsg,
- ?line {ok,_Parts}='TCAPPackage':decode_part(Key,ExVal),
+ Val = 'TCAPPackage_msg':val('PackageType', queryWithPerm),
+ {ok,B} = 'TCAPPackage':encode('PackageType', Val),
+ {ok,ExMsg}='TCAPPackage':decode_PackageType(B),
+ {_,{_,_,_,{Key,ExVal}}} = ExMsg,
+ {ok,_Parts} = 'TCAPPackage':decode_part(Key, ExVal),
- ?line Val2 = 'TCAPPackage_msg':val('TransactionPDU'),
- ?line {ok,B2} = 'TCAPPackage':encode('TransactionPDU',Val2),
- {ok,ExMsg2}='TCAPPackage':decode_TransactionPDU(B2),
- ?line {_,_,_,{Key2,ExVal2}}=ExMsg2,
- ?line {ok,_Parts2}='TCAPPackage':decode_part(Key2,ExVal2),
+ Val2 = 'TCAPPackage_msg':val('TransactionPDU'),
+ {ok,B2} = 'TCAPPackage':encode('TransactionPDU', Val2),
+ {ok,ExMsg2} = 'TCAPPackage':decode_TransactionPDU(B2),
+ {_,_,_,{Key2,ExVal2}} = ExMsg2,
+ {ok,_Parts2} = 'TCAPPackage':decode_part(Key2, ExVal2),
- ?line Val3 = 'TCAPPackage_msg':val('PackageType',response),
- ?line {ok,B3} = asn1_wrapper:encode('TCAPPackage','PackageType',Val3),
- ?line {ok,ExMsg3}='TCAPPackage':decode_PackageType(list_to_binary(B3)),
- ?line {_,{_,_,_,{Key3,ExVal3}}}=ExMsg3,
- ?line {ok,_Parts3}='TCAPPackage':decode_part(Key3,ExVal3).
+ Val3 = 'TCAPPackage_msg':val('PackageType', response),
+ {ok,B3} = 'TCAPPackage':encode('PackageType', Val3),
+ {ok,ExMsg3} = 'TCAPPackage':decode_PackageType(B3),
+ {_,{_,_,_,{Key3,ExVal3}}} = ExMsg3,
+ {ok,_Parts3}='TCAPPackage':decode_part(Key3, ExVal3).
+enc_dec(T, V0) ->
+ M = 'TCAPPackage',
+ {ok,Enc} = M:encode(T, V0),
+ {ok,V} = M:decode(T, Enc),
+ V.
diff --git a/lib/asn1/test/testTimer.erl b/lib/asn1/test/testTimer.erl
index cd7ceb5630..0f02bab6e0 100644
--- a/lib/asn1/test/testTimer.erl
+++ b/lib/asn1/test/testTimer.erl
@@ -18,9 +18,7 @@
%%
%%
-module(testTimer).
-
--compile(export_all).
-%%-export([Function/Arity, ...]).
+-export([go/2]).
-include_lib("test_server/include/test_server.hrl").
@@ -127,7 +125,7 @@ val() ->
{'H323-UserInformation_user-data',24,"O"}}.
-go(Config,Enc) ->
+go(Config, _Enc) ->
?line true = code:add_patha(?config(priv_dir,Config)),
Module = 'H323-MESSAGES',
@@ -137,13 +135,12 @@ go(Config,Enc) ->
CompileOptions = compile_options(),
- ?line {ValWr, done} = timer:tc(?MODULE, encode, [?times, Module, Type, Value]),
+ {ValWr,done} = timer:tc(fun() -> encode(?times, Module, Type, Value) end),
?line io:format("ASN1 encode ~p: ~p micro~n", [CompileOptions, ValWr / ?times]),
- ?line done = decode(2,Module,Type,Bytes,Enc),
+ done = decode(2, Module, Type, Bytes),
- ?line {ValRead, done} = timer:tc(?MODULE, decode, [?times, Module,
- Type, Bytes,Enc]),
+ {ValRead,done} = timer:tc(fun() -> decode(?times, Module, Type, Bytes) end),
?line io:format("ASN1 decode ~p: ~p micro~n", [CompileOptions, ValRead /?times]),
@@ -162,11 +159,11 @@ encode(N, Module,Type,Value) ->
end,
encode(N-1, Module,Type,Value).
-decode(0, _Module,_Type,_Value,_Erule) ->
+decode(0, _Module, _Type, _Value) ->
done;
-decode(N, Module,Type,Value,Erule) ->
- {ok,_B} = asn1rt:decode(Module,Type,Value),
- decode(N-1, Module,Type,Value,Erule).
+decode(N, Module, Type, Value) ->
+ {ok,_B} = asn1rt:decode(Module, Type, Value),
+ decode(N-1, Module, Type, Value).
compile_options() ->
{ok,Info} = asn1rt:info('H323-MESSAGES'),
diff --git a/lib/asn1/test/testTypeValueNotation.erl b/lib/asn1/test/testTypeValueNotation.erl
index 61d69edd0e..b46d7177f5 100644
--- a/lib/asn1/test/testTypeValueNotation.erl
+++ b/lib/asn1/test/testTypeValueNotation.erl
@@ -24,13 +24,15 @@
-record('Seq', {octstr, int, bool, enum, bitstr, null, oid, vstr}).
main(_Rule, _Option) ->
- Value1 = #'Seq'{octstr = [1, 2, 3, 4],
- int = 12,
- bool = true,
- enum = a,
- bitstr = <<2#1010:4>>,
- null = 'NULL',
- oid = {1, 2, 55},
- vstr = "Hello World"},
- {ok, Bytes} = asn1_wrapper:encode('SeqTypeRefPrim', 'Seq', Value1),
- {ok, Value1} = asn1_wrapper:decode('SeqTypeRefPrim', 'Seq', Bytes).
+ Value = #'Seq'{octstr = [1, 2, 3, 4],
+ int = 12,
+ bool = true,
+ enum = a,
+ bitstr = <<2#1010:4>>,
+ null = 'NULL',
+ oid = {1, 2, 55},
+ vstr = "Hello World"},
+ roundtrip('Seq', Value).
+
+roundtrip(T, V) ->
+ asn1_test_lib:roundtrip('SeqTypeRefPrim', T, V).
diff --git a/lib/asn1/test/testWSParamClass.erl b/lib/asn1/test/testWSParamClass.erl
index ae67ca8b81..66ba56a6d8 100644
--- a/lib/asn1/test/testWSParamClass.erl
+++ b/lib/asn1/test/testWSParamClass.erl
@@ -11,7 +11,4 @@ main(_) ->
ok.
roundtrip(Data) ->
- IF = 'InformationFramework',
- {ok,Enc} = asn1_wrapper:encode(IF, 'Attribute', Data),
- {ok,Data} = IF:decode('Attribute', Enc),
- ok.
+ asn1_test_lib:roundtrip('InformationFramework', 'Attribute', Data).
diff --git a/lib/asn1/test/testX420.erl b/lib/asn1/test/testX420.erl
index 70bdb0640d..4ddc55dc16 100644
--- a/lib/asn1/test/testX420.erl
+++ b/lib/asn1/test/testX420.erl
@@ -27,21 +27,11 @@
compile(Erule, Options, Config) ->
- Specs = specs(),
- 99 = length(Specs),
- ok = compile_loop(Erule,Specs,Options,Config).
-
-compile_loop(_Erule, [], _Options, _Config) ->
- ok;
-compile_loop(Erule, [Spec|Specs], Options, Config)
- when Erule =:= ber; Erule =:= per ->
+ Specs0 = specs(),
+ 99 = length(Specs0),
CaseDir = ?config(case_dir, Config),
- asn1_test_lib:compile(filename:join([x420, Spec]), Config,
- [Erule, {i, CaseDir} | Options]),
- compile_loop(Erule, Specs, Options, Config);
-compile_loop(_Erule, _Specs, _Options, _Config) ->
- ok.
-
+ Specs = [filename:join(x420, Spec) || Spec <- Specs0],
+ asn1_test_lib:compile_all(Specs, Config, [Erule,{i,CaseDir}|Options]).
specs() ->
["ACSE-1", "AuthenticationFramework", "BasicAccessControl",
@@ -93,9 +83,9 @@ specs() ->
ticket7759(_Erule,_Config) ->
Encoded = encoded_msg(),
io:format("Testing ticket7759 ...~n",[]),
- ?line {ok, ContentInfo} = asn1_wrapper:decode('PKCS7','ContentInfo',Encoded),
- ?line {'ContentInfo',_Id,PKCS7_content} = ContentInfo,
- ?line {ok,_} = asn1_wrapper:decode('PKCS7','SignedData',PKCS7_content),
+ {ok, ContentInfo} = 'PKCS7':decode('ContentInfo',Encoded),
+ {'ContentInfo',_Id,PKCS7_content} = ContentInfo,
+ {ok,_} = 'PKCS7':decode('SignedData',PKCS7_content),
ok.
diff --git a/lib/asn1/test/test_driver_load.erl b/lib/asn1/test/test_driver_load.erl
deleted file mode 100644
index e0e6602046..0000000000
--- a/lib/asn1/test/test_driver_load.erl
+++ /dev/null
@@ -1,45 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-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%
-%%
-%%
--module(test_driver_load).
-
--export([test/1,encode/0]).
-
--include_lib("test_server/include/test_server.hrl").
-
-
-test(0) ->
- ok;
-test(N) ->
- spawn(?MODULE,encode,[]),
- test(N-1).
-
-encode() ->
- ?line Msg = msg(),
- ?line {ok,_}=asn1_wrapper:encode('P-Record','PersonnelRecord',Msg),
- ok.
-
-msg() ->
- {'PersonnelRecord',{'Name',"John","P","Smith"},
- "Director",
- 51,
- "19710917",
- {'Name',"Mary","T","Smith"},
- [{'ChildInformation',{'Name',"Ralph","T","Smith"},"19571111"},{'ChildInformation',{'Name',"Susan","B","Jones"},"19590717"}]}.
-
diff --git a/lib/asn1/test/test_modified_x420.erl b/lib/asn1/test/test_modified_x420.erl
index a525fd6ae1..0df72a1831 100644
--- a/lib/asn1/test/test_modified_x420.erl
+++ b/lib/asn1/test/test_modified_x420.erl
@@ -26,8 +26,9 @@ test(Config) ->
DataDir = ?config(data_dir,Config),
Der = read_pem(filename:join([DataDir,modified_x420,"p7_signed_data.pem"])),
- {ok,{_,_,SignedData}} = asn1_wrapper:decode('PKCS7', 'ContentInfo', Der),
- {ok,_} = asn1_wrapper:decode('PKCS7', 'SignedData', SignedData).
+ {ok,{_,_,SignedData}} = 'PKCS7':decode( 'ContentInfo', Der),
+ {ok,_} = 'PKCS7':decode('SignedData', SignedData),
+ ok.
read_pem(File) ->
{ok,Bin} = file:read_file(File),
diff --git a/lib/asn1/test/test_partial_incomplete_decode.erl b/lib/asn1/test/test_partial_incomplete_decode.erl
index 8ede06938d..4a8a4cd74c 100644
--- a/lib/asn1/test/test_partial_incomplete_decode.erl
+++ b/lib/asn1/test/test_partial_incomplete_decode.erl
@@ -25,84 +25,57 @@
test(Config) ->
FMsg = msg('F'),
- ?line {ok,Bytes} = asn1_wrapper:encode('PartialDecSeq','F',FMsg),
- ?line {ok,_} = asn1_wrapper:decode('PartialDecSeq','F',Bytes),
- ?line {ok,IncFMsg} =
- 'PartialDecSeq':decode_F_fb_incomplete(list_to_binary(Bytes)),
- ?line decode_parts('F',IncFMsg),
+ Bytes1 = roundtrip('PartialDecSeq', 'F', FMsg),
+ {ok,IncFMsg} = 'PartialDecSeq':decode_F_fb_incomplete(Bytes1),
+ decode_parts('F', IncFMsg),
+ {ok,IncF2Msg} = 'PartialDecSeq':decode_F_fb_exclusive2(Bytes1),
+ decode_parts('F2', IncF2Msg),
DMsg = msg('D'),
- ?line {ok,Bytes2} = asn1_wrapper:encode('PartialDecSeq','D',DMsg),
- ?line {ok,_} = asn1_wrapper:decode('PartialDecSeq','D',Bytes2),
- ?line {ok,IncDMsg} =
- 'PartialDecSeq':decode_D_incomplete(list_to_binary(Bytes2)),
- ?line decode_parts('D',IncDMsg),
-
- ?line {ok,IncF2Msg} =
- 'PartialDecSeq':decode_F_fb_exclusive2(list_to_binary(Bytes)),
- ?line decode_parts('F2',IncF2Msg),
+ Bytes2 = roundtrip('PartialDecSeq', 'D', DMsg),
+ {ok,IncDMsg} = 'PartialDecSeq':decode_D_incomplete(Bytes2),
+ decode_parts('D', IncDMsg),
F3Msg = msg('F3'),
- ?line {ok,BytesF3} = asn1_wrapper:encode('PartialDecSeq','F',F3Msg),
- ?line {ok,_} = asn1_wrapper:decode('PartialDecSeq','F',BytesF3),
- ?line {ok,IncF3Msg} =
- 'PartialDecSeq':decode_F_fb_exclusive3(list_to_binary(BytesF3)),
- ?line decode_parts('F3',IncF3Msg),
-
-
- AMsg =msg('A'),
- ?line {ok,Bytes3} = asn1_wrapper:encode('PartialDecSeq2','A',AMsg),
- ?line {ok,_} = asn1_wrapper:decode('PartialDecSeq2','A',Bytes3),
- ?line {ok,IncFMsg3} =
- 'PartialDecSeq2':decode_A_c_b_incomplete(list_to_binary(Bytes3)),
- ?line decode_parts('A',IncFMsg3),
+ BytesF3 = roundtrip('PartialDecSeq', 'F', F3Msg),
+ {ok,IncF3Msg} = 'PartialDecSeq':decode_F_fb_exclusive3(BytesF3),
+ decode_parts('F3', IncF3Msg),
+
+ AMsg = msg('A'),
+ Bytes3 = roundtrip('PartialDecSeq2', 'A', AMsg),
+ {ok,IncFMsg3} = 'PartialDecSeq2':decode_A_c_b_incomplete(Bytes3),
+ decode_parts('A', IncFMsg3),
MyHTTPMsg = msg('GetRequest'),
- ?line {ok,Bytes4} = asn1_wrapper:encode('PartialDecMyHTTP',
- 'GetRequest',MyHTTPMsg),
- ?line {ok,_} = asn1_wrapper:decode('PartialDecMyHTTP','GetRequest',
- Bytes4),
- ?line {ok,IncFMsg4} =
- 'PartialDecMyHTTP':decode_GetRequest_incomplete(list_to_binary(Bytes4)),
- ?line decode_parts('GetRequest',IncFMsg4),
+ Bytes4 = roundtrip('PartialDecMyHTTP', 'GetRequest', MyHTTPMsg),
+ {ok,IncFMsg4} = 'PartialDecMyHTTP':decode_GetRequest_incomplete(Bytes4),
+ decode_parts('GetRequest', IncFMsg4),
MsgS1_1 = msg('S1_1'),
- ?line {ok,Bytes5} = asn1_wrapper:encode('PartialDecSeq3','S1',MsgS1_1),
- ?line {ok,_} = asn1_wrapper:decode('PartialDecSeq3','S1',Bytes5),
- ?line {ok,IncFMsg5} =
- 'PartialDecSeq3':decode_S1_incomplete(list_to_binary(Bytes5)),
- ?line decode_parts('S1_1',IncFMsg5),
+ Bytes5 = roundtrip('PartialDecSeq3', 'S1', MsgS1_1),
+ {ok,IncFMsg5} = 'PartialDecSeq3':decode_S1_incomplete(Bytes5),
+ decode_parts('S1_1', IncFMsg5),
MsgS1_2 = msg('S1_2'),
- ?line {ok,Bytes6} = asn1_wrapper:encode('PartialDecSeq3','S1',MsgS1_2),
- ?line {ok,IncFMsg6} =
- 'PartialDecSeq3':decode_S1_incomplete(list_to_binary(Bytes6)),
- ?line ok = decode_parts('S1_2',IncFMsg6),
+ Bytes6 = roundtrip('PartialDecSeq3', 'S1', MsgS1_2),
+ {ok,IncFMsg6} = 'PartialDecSeq3':decode_S1_incomplete(Bytes6),
+ decode_parts('S1_2', IncFMsg6),
%% test of MEDIA-GATEWAY-CONTROL
test_megaco(Config),
ok.
test_megaco(Config) ->
- ?line DataDir = ?config(data_dir,Config),
- Mod='MEDIA-GATEWAY-CONTROL',
- ?line {ok,FilenameList} = file:list_dir(filename:join([DataDir,
- megacomessages])),
- %% remove any junk files that may be in the megacomessage directory
- Pred = fun(X) ->
- case lists:reverse(X) of
- [$l,$a,$v,$.|_R] ->true;
- _ -> false
- end
- end,
- MegacoMsgFilenameList = lists:filter(Pred,FilenameList),
- Fun = fun(F) ->
- M = read_msg(filename:join([DataDir,megacomessages,F])),
- ?line {ok,B} = asn1_wrapper:encode(Mod,element(1,M),M),
- ?line exclusive_decode(list_to_binary(B),F)
- end,
- ?line lists:foreach(Fun,MegacoMsgFilenameList),
- ok.
+ DataDir = ?config(data_dir, Config),
+ Files = filelib:wildcard(filename:join([DataDir,megacomessages,"*.val"])),
+ Mod = 'MEDIA-GATEWAY-CONTROL',
+ lists:foreach(fun(File) ->
+ {ok,Bin} = file:read_file(File),
+ V = binary_to_term(Bin),
+ T = element(1, V),
+ Enc = roundtrip(Mod, T, V),
+ exclusive_decode(Enc, File)
+ end, Files).
exclusive_decode(Bin,F) ->
Mod='MEDIA-GATEWAY-CONTROL',
@@ -113,15 +86,6 @@ exclusive_decode(Bin,F) ->
?line {ok,_} = Mod:decode_part(MsgMBodyKey,MsgMBody),
ok.
-
-read_msg(File) ->
- case file:read_file(File) of
- {ok,Bin} ->
- binary_to_term(Bin);
- _ ->
- io:format("couldn't read file ~p~n",[File])
- end.
-
decode_parts('F',PartDecMsg) ->
?line {fb,{'E',35,{NameE_b,ListBinE_b},false,{NameE_d,BinE_d}}} = PartDecMsg,
?line {ok,[{'D',3,true}|_]} = 'PartialDecSeq':decode_part(NameE_b,ListBinE_b),
@@ -200,7 +164,10 @@ msg('A') ->
{'A',12,{c,{'S',true,false}},{b,{'A_c_b',false,false}}};
msg('GetRequest') ->
- {'GetRequest',true,false,{'AcceptTypes',[1,1,1,1],["hell","othe","reho","peyo","uare","fine"]},"IamfineThankYOu"};
+ {'GetRequest',true,false,
+ {'AcceptTypes',[html,'plain-text',gif,jpeg],
+ ["hell","othe","reho","peyo","uare","fine"]},
+ "IamfineThankYOu"};
msg('S1_1') ->
{'S1',14,msg('S2'),msg('C1_a'),msg('SO1')};
@@ -213,10 +180,13 @@ msg('C1_a') ->
msg('C1_b') ->
{b,{'C1_b',11,true,msg('S4')}};
msg('S3') ->
- {'S3',10,"PrintableString","OCTETSTRING",[1,1,1,1]};
+ {'S3',10,"PrintableString","OCTETSTRING",[one,two,three,four]};
msg('S4') ->
{'S4',msg('Name'),"MSc"};
msg('SO1') ->
[msg('Name'),msg('Name'),msg('Name')];
msg('Name') ->
{'Name',"Hans","HCA","Andersen"}.
+
+roundtrip(M, T, V) ->
+ asn1_test_lib:roundtrip_enc(M, T, V).
diff --git a/lib/asn1/test/test_selective_decode.erl b/lib/asn1/test/test_selective_decode.erl
index ebe1296cf3..f42f24e0e3 100644
--- a/lib/asn1/test/test_selective_decode.erl
+++ b/lib/asn1/test/test_selective_decode.erl
@@ -18,39 +18,39 @@
%%
%%
-module(test_selective_decode).
-
-export([test/0]).
-include_lib("test_server/include/test_server.hrl").
-
test() ->
FMsg = msg('F'),
- ?line {ok,Bytes} = asn1_wrapper:encode('PartialDecSeq','F',FMsg),
- ?line {ok,3} =
- 'PartialDecSeq':selected_decode_F1(list_to_binary(Bytes)),
- ?line {ok,[{'D',3,true},{'D',4,false},{'D',5,true},{'D',6,true},{'D',7,false},{'D',8,true},{'D',9,true},{'D',10,false},{'D',11,true},{'D',12,true},{'D',13,false},{'D',14,true}]} = 'PartialDecSeq':selected_decode_F2(list_to_binary(Bytes)),
- ?line {ok,{'D',3,true}} = 'PartialDecSeq':selected_decode_F3(list_to_binary(Bytes)),
-
- ?line {ok,17} = 'PartialDecSeq':selected_decode_F4(list_to_binary(Bytes)),
+ Bytes = roundtrip('PartialDecSeq', 'F', FMsg),
+ {ok,3} = 'PartialDecSeq':selected_decode_F1(Bytes),
+ {ok,[{'D',3,true},{'D',4,false},{'D',5,true},{'D',6,true},
+ {'D',7,false},{'D',8,true},{'D',9,true},{'D',10,false},
+ {'D',11,true},{'D',12,true},{'D',13,false},{'D',14,true}]} =
+ 'PartialDecSeq':selected_decode_F2(Bytes),
+ {ok,{'D',3,true}} = 'PartialDecSeq':selected_decode_F3(Bytes),
+ {ok,17} = 'PartialDecSeq':selected_decode_F4(Bytes),
EMsg = msg('E'),
- ?line {ok,Bytes2} = asn1_wrapper:encode('PartialDecSeq','E',EMsg),
- ?line {ok,14} = 'PartialDecSeq':selected_decode_E1(list_to_binary(Bytes2)),
+ Bytes2 = roundtrip('PartialDecSeq', 'E', EMsg),
+ {ok,14} = 'PartialDecSeq':selected_decode_E1(Bytes2),
+
MGCMsg = msg('M-G-C'),
- ?line {ok,Bytes3} = asn1_wrapper:encode('MEDIA-GATEWAY-CONTROL',
- 'MegacoMessage',MGCMsg),
- ?line {ok,1} = 'MEDIA-GATEWAY-CONTROL':decode_MegacoMessage_selective(list_to_binary(Bytes3)),
+ Bytes3 = roundtrip('MEDIA-GATEWAY-CONTROL', 'MegacoMessage', MGCMsg),
+ {ok,1} = 'MEDIA-GATEWAY-CONTROL':decode_MegacoMessage_selective(Bytes3),
PRecMsg = {'PersonnelRecord',{'Name',"Sven","S","Svensson"},
"manager",123,"20000202",{'Name',"Inga","K","Svensson"},
asn1_DEFAULT},
- ?line {ok,Bytes4} = asn1_wrapper:encode('P-Record','PersonnelRecord',
- PRecMsg),
- ?line {ok,_} = 'P-Record':sel_dec(list_to_binary(Bytes4)),
- ok.
-
+ PRecMsgDec = {'PersonnelRecord',{'Name',"Sven","S","Svensson"},
+ "manager",123,"20000202",{'Name',"Inga","K","Svensson"},
+ []},
+ Bytes4 = roundtrip('P-Record', 'PersonnelRecord', PRecMsg, PRecMsgDec),
+ {ok,_} = 'P-Record':sel_dec(Bytes4),
+ ok.
msg('F') ->
{fb,{'E',35,[{'D',3,true},{'D',4,false},{'D',5,true},{'D',6,true},{'D',7,false},{'D',8,true},{'D',9,true},{'D',10,false},{'D',11,true},{'D',12,true},{'D',13,false},{'D',14,true}],false,{da,[{'A',16,{'D',17,true}}]}}};
@@ -60,3 +60,10 @@ msg('E') ->
msg('M-G-C') ->
{'MegacoMessage',asn1_NOVALUE,{'Message',1,{ip4Address,{'IP4Address',[125,125,125,111],55555}},{transactions,[{transactionReply,{'TransactionReply',50007,asn1_NOVALUE,{actionReplies,[{'ActionReply',0,asn1_NOVALUE,asn1_NOVALUE,[{auditValueReply,{auditResult,{'AuditResult',{'TerminationID',[],[255,255,255]},[{mediaDescriptor,{'MediaDescriptor',asn1_NOVALUE,{multiStream,[{'StreamDescriptor',1,{'StreamParms',{'LocalControlDescriptor',sendRecv,asn1_NOVALUE,asn1_NOVALUE,[{'PropertyParm',[0,11,0,7],[[52,48]],asn1_NOVALUE}]},{'LocalRemoteDescriptor',[[{'PropertyParm',[0,0,176,1],[[48]],asn1_NOVALUE},{'PropertyParm',[0,0,176,8],[[73,78,32,73,80,52,32,49,50,53,46,49,50,53,46,49,50,53,46,49,49,49]],asn1_NOVALUE},{'PropertyParm',[0,0,176,15],[[97,117,100,105,111,32,49,49,49,49,32,82,84,80,47,65,86,80,32,32,52]],asn1_NOVALUE},{'PropertyParm',[0,0,176,12],[[112,116,105,109,101,58,51,48]],asn1_NOVALUE}]]},{'LocalRemoteDescriptor',[[{'PropertyParm',[0,0,176,1],[[48]],asn1_NOVALUE},{'PropertyParm',[0,0,176,8],[[73,78,32,73,80,52,32,49,50,52,46,49,50,52,46,49,50,52,46,50,50,50]],asn1_NOVALUE},{'PropertyParm',[0,0,176,15],[[97,117,100,105,111,32,50,50,50,50,32,82,84,80,47,65,86,80,32,32,52]],asn1_NOVALUE},{'PropertyParm',[0,0,176,12],[[112,116,105,109,101,58,51,48]],asn1_NOVALUE}]]}}}]}}},{packagesDescriptor,[{'PackagesItem',[0,11],1},{'PackagesItem',[0,11],1}]},{statisticsDescriptor,[{'StatisticsParameter',[0,12,0,4],[[49,50,48,48]]},{'StatisticsParameter',[0,11,0,2],[[54,50,51,48,48]]},{'StatisticsParameter',[0,12,0,5],[[55,48,48]]},{'StatisticsParameter',[0,11,0,3],[[52,53,49,48,48]]},{'StatisticsParameter',[0,12,0,6],[[48,46,50]]},{'StatisticsParameter',[0,12,0,7],[[50,48]]},{'StatisticsParameter',[0,12,0,8],[[52,48]]}]}]}}}]}]}}}]}}}.
+
+
+roundtrip(M, T, V) ->
+ asn1_test_lib:roundtrip_enc(M, T, V).
+
+roundtrip(M, T, V, E) ->
+ asn1_test_lib:roundtrip_enc(M, T, V, E).
diff --git a/lib/asn1/test/test_special_decode_performance.erl b/lib/asn1/test/test_special_decode_performance.erl
index 7dfab1f25a..0f52ae4cd2 100644
--- a/lib/asn1/test/test_special_decode_performance.erl
+++ b/lib/asn1/test/test_special_decode_performance.erl
@@ -19,7 +19,7 @@
%%
-module(test_special_decode_performance).
--export([go/1,loop2/4,loop1/5]).
+-export([go/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -49,7 +49,7 @@ go1(_,_,[],_,_,AccTime) ->
%% go1 for common decode
go1(common,Mod,_,Bin,N,_) ->
?line TT=get_top_type(Mod),
- ?line {Time,Result}=timer:tc(?MODULE,loop1,[Mod,decode,TT,Bin,N]),
+ {Time,Result} = timer:tc(fun() -> loop1(Mod, decode, TT, Bin, N) end),
case Result of
{ok,_R1} ->
io:format("common Decode ~p:decode, ~p times on time ~p~n",
@@ -59,7 +59,7 @@ go1(common,Mod,_,Bin,N,_) ->
end,
Time;
go1(Dec,Mod,[F|Fs],Bin,N,AccTime) ->
- ?line {Time,Result}=timer:tc(?MODULE,loop2,[Mod,F,Bin,N]),
+ {Time,Result}=timer:tc(fun() -> loop2(Mod, F, Bin, N) end),
case Result of
{ok,_R1} ->
io:format("~p Decode ~p:~p, ~p times on time ~p~n",[Dec,Mod,F,N,Time]);
diff --git a/lib/asn1/test/test_undecoded_rest.erl b/lib/asn1/test/test_undecoded_rest.erl
index 36fd26ed59..91e614d38a 100644
--- a/lib/asn1/test/test_undecoded_rest.erl
+++ b/lib/asn1/test/test_undecoded_rest.erl
@@ -26,28 +26,42 @@
%% testing OTP-5104
-test(Opt, Config) ->
- {ok, Msg} = asn1ct:value('P-Record', 'PersonnelRecord',
- [{i, ?config(case_dir, Config)}]),
- {ok, Bytes} = asn1_wrapper:encode('P-Record', 'PersonnelRecord', Msg),
- Bytes2 = if is_list(Bytes) ->
- Bytes ++ [55, 55, 55];
- is_binary(Bytes) ->
- iolist_to_binary([Bytes, <<55, 55, 55>>])
- end,
- case Opt of
- undec_rest ->
- {ok, Msg, R} = asn1_wrapper:decode('P-Record', 'PersonnelRecord',
- Bytes2),
+test(Opts, Config) ->
+ {ok,Msg} = asn1ct:value('P-Record', 'PersonnelRecord',
+ [{i,?config(case_dir, Config)}]),
+ Bytes0 = encode(Opts, 'PersonnelRecord', Msg),
+ Bytes1 = iolist_to_binary([Bytes0, <<55,55,55>>]),
+ case proplists:get_bool(undec_rest, Opts) of
+ true ->
+ {Msg,R} = decode(Opts, 'PersonnelRecord', Bytes1),
case R of
- <<55, 55, 55>> -> ok;
- [55, 55, 55] -> ok;
+ <<55,55,55>> ->
+ ok;
BStr when is_bitstring(BStr) ->
PadLen = (8 - (bit_size(BStr) rem 8)) rem 8,
- <<0, 55, 55, 55>> = <<0:PadLen, BStr/bitstring>>
+ <<0,55,55,55>> = <<0:PadLen, BStr/bitstring>>
end;
- _ ->
- {ok, Msg} = asn1_wrapper:decode('P-Record', 'PersonnelRecord',
- Bytes2)
+ false ->
+ Msg = decode(Opts, 'PersonnelRecord', Bytes1)
end,
ok.
+
+encode(Opts, T, V) ->
+ M = 'P-Record',
+ case proplists:get_bool(no_ok_wrapper, Opts) of
+ false ->
+ {ok,Enc} = M:encode(T, V),
+ Enc;
+ true ->
+ Enc = M:encode(T, V),
+ true = is_binary(Enc),
+ Enc
+ end.
+
+decode(Opts, T, E) ->
+ M = 'P-Record',
+ case {proplists:get_bool(no_ok_wrapper, Opts),M:decode(T, E)} of
+ {false,{ok,Val}} -> Val;
+ {false,{ok,Val,Rest}} -> {Val,Rest};
+ {true,Result} -> Result
+ end.
diff --git a/lib/asn1/test/test_x691.erl b/lib/asn1/test/test_x691.erl
index dcfa211d80..9b141e2389 100644
--- a/lib/asn1/test/test_x691.erl
+++ b/lib/asn1/test/test_x691.erl
@@ -18,50 +18,25 @@
%%
%%
-module(test_x691).
-
--export([cases/2]).
+-export([cases/1]).
-include_lib("test_server/include/test_server.hrl").
-cases(Erule,Variant) ->
- MsgA1 = a1(),
- ?line {ok,B1} = asn1_wrapper:encode('P-RecordA1','PersonnelRecord',MsgA1),
- ?line {ok,MsgA1} = asn1_wrapper:decode('P-RecordA1','PersonnelRecord',B1),
- io:format("compare_format(~p,B1) ->~p~nencval(a1,~p,binary) ->~p~n",
- [Erule,
- compare_format(Erule,B1),
- Variant,
- encval(a1,Variant,binary)]),
- ?line true = (compare_format(Erule,B1) == encval(a1,Variant,binary)),
-
- MsgA2 = a2(),
- ?line {ok,B2} = asn1_wrapper:encode('P-RecordA2','PersonnelRecord',MsgA2),
- ?line {ok,MsgA2} = asn1_wrapper:decode('P-RecordA2','PersonnelRecord',B2),
- io:format("compare_format(~p,B2) ->~p~nencval(a2,~p,binary) ->~p~n",
- [Erule,
- compare_format(Erule,B2),
- Variant,
- encval(a2,Variant,binary)]),
- ?line true = (compare_format(Erule,B2) == encval(a2,Variant,binary)),
-
- MsgA3 = a3(),
- ?line {ok,B3} = asn1_wrapper:encode('P-RecordA3','PersonnelRecord',MsgA3),
- ?line {ok,MsgA3} = asn1_wrapper:decode('P-RecordA3','PersonnelRecord',B3),
- io:format("compare_format(~p,B3) ->~p~nencval(a3,~p,binary) ->~p~n",
- [Erule,
- compare_format(Erule,B3),
- Variant,
- encval(a3,Variant,binary)]),
- ?line true = (compare_format(Erule,B3) == encval(a3,Variant,binary)).
-
-compare_format(Erule,Val) when is_list(Val) ->
- compare_format(Erule,list_to_binary(Val));
-%% compare_format(per,Val) ->
-%% binary_to_list(Val);
-compare_format(_,Val) ->
- Val.
-
-a1() ->
+cases(Erule) ->
+ _ = [begin
+ Mod = module(Name),
+ Msg = msg(Name),
+ Hex = encval(Name, Erule),
+ Enc = asn1_test_lib:hex_to_bin(Hex),
+ Enc = asn1_test_lib:roundtrip_enc(Mod, 'PersonnelRecord', Msg)
+ end || Name <- [a1,a2,a3]],
+ ok.
+
+module(a1) -> 'P-RecordA1';
+module(a2) -> 'P-RecordA2';
+module(a3) -> 'P-RecordA3'.
+
+msg(a1) ->
{'PersonnelRecord',
{'Name',"John", "P", "Smith"},
"Director",
@@ -73,12 +48,10 @@ a1() ->
"19571111"},
{'ChildInformation',
{'Name', "Susan", "B", "Jones"},
- "19590717"}]}.
-
-a2() ->
- a1().
-
-a3() ->
+ "19590717"}]};
+msg(a2) ->
+ msg(a1);
+msg(a3) ->
{'PersonnelRecord',
{'Name',"John", "P", "Smith"},
"Director",
@@ -94,119 +67,15 @@ a3() ->
"19590717",
female}]}.
-encval(An,Variant,Encoding) when Encoding == hex; Encoding == binary ->
- Msg = encval(An,Variant),
- encoding(Encoding,Msg).
-
-encval(a1,aligned) ->
+encval(a1, per) ->
"80044A6F 686E0150 05536D69 74680133 08446972 6563746F 72083139 37313039 3137044D 61727901 5405536D 69746802 0552616C 70680154 05536D69 74680831 39353731 31313105 53757361 6E014205 4A6F6E65 73083139 35393037 3137";
-encval(a1,unaligned) ->
+encval(a1, uper) ->
"824ADFA3 700D005A 7B74F4D0 02661113 4F2CB8FA 6FE410C5 CB762C1C B16E0937 0F2F2035 0169EDD3 D340102D 2C3B3868 01A80B4F 6E9E9A02 18B96ADD 8B162C41 69F5E787 700C2059 5BF765E6 10C5CB57 2C1BB16E";
-encval(a2,aligned) ->
+encval(a2, per) ->
"864A6F68 6E501053 6D697468 01330844 69726563 746F7219 7109170C 4D617279 5410536D 69746802 1052616C 70685410 536D6974 68195711 11105375 73616E42 104A6F6E 65731959 0717";
-encval(a2,unaligned) ->
+encval(a2, uper) ->
"865D51D2 888A5125 F1809984 44D3CB2E 3E9BF90C B8848B86 7396E8A8 8A5125F1 81089B93 D71AA229 4497C632 AE222222 985CE521 885D54C1 70CAC838 B8";
-encval(a3,aligned) ->
+encval(a3, per) ->
"40C04A6F 686E5008 536D6974 68000033 08446972 6563746F 72001971 0917034D 61727954 08536D69 74680100 52616C70 68540853 6D697468 00195711 11820053 7573616E 42084A6F 6E657300 19590717 010140";
-encval(a3,unaligned) ->
+encval(a3, uper) ->
"40CBAA3A 5108A512 5F180330 889A7965 C7D37F20 CB8848B8 19CE5BA2 A114A24B E3011372 7AE35422 94497C61 95711118 22985CE5 21842EAA 60B832B2 0E2E0202 80".
-
-encoding(binary,Msg) ->
- list_to_binary(bin(Msg));
-encoding(hex,Msg) ->
- hex(Msg).
-
-bin(Msg) ->
- HexList = hex(Msg),
- Fun = fun([H1,H2|Rest],F) -> [(H1 bsl 4) + H2|F(Rest,F)];([],_) -> [] end,
- Fun(HexList,Fun).
-
-hex(Msg) ->
- [to_hex(X)||X <- Msg,X /= $ ].
-
-to_hex(I) when I >= $0, I =< $9 ->
- I-48;
-to_hex(C) when C >= $A,C =< $F ->
- C - 55.
-
-%% ex('EUTRA','BCCH-DL-SCH-Message',1) ->
-%% {'BCCH-DL-SCH-Message',
-%% {c1,
-%% {systemInformation1,
-%% {'SystemInformationBlockType1',
-%% {'SystemInformationBlockType1_cellAccessRelatedInformation',
-%% [{'SystemInformationBlockType1_cellAccessRelatedInformation_SOF',
-%% {'PLMN-Identity'},
-%% true},
-%% {'SystemInformationBlockType1_cellAccessRelatedInformation_SOF',
-%% {'PLMN-Identity'},
-%% false},
-%% {'SystemInformationBlockType1_cellAccessRelatedInformation_SOF',
-%% {'PLMN-Identity'},
-%% true}],
-%% {'TrackingAreaCode'},
-%% {'CellIdentity'},
-%% false,
-%% true,
-%% true,
-%% true},
-%% {'SystemInformationBlockType1_cellSelectionInfo',
-%% -50},
-%% 24,
-%% [{'SystemInformationBlockType1_schedulinInformation_SOF',
-%% {'SystemInformationBlockType1_schedulinInformation_SOF_si-MessageType'},
-%% ms320,
-%% {'SystemInformationBlockType1_schedulinInformation_SOF_sib-MappingInfo'}
-%% }],
-%% 0
-%% }
-%% }
-%% }
-%% }.
-
-%% eutra1(msg) ->
-%% {'BCCH-BCH-Message',{'MasterInformationBlock',[0,1,0,1],[1,0,1,0],{'PHICH-Configuration',short,ffs},[1,0,1,0,0,0,0,0]}};
-%% eutra1(result) ->
-%% <<90,80,0>>.
-
-%% eutra2(msg) ->
-%% {'BCCH-DL-SCH-Message',
-%% {c1,
-%% {systemInformation1,
-%% {'SystemInformationBlockType1',
-%% {'SystemInformationBlockType1_cellAccessRelatedInformation',
-%% [{'SystemInformationBlockType1_cellAccessRelatedInformation_plmn-IdentityList_SEQOF',{'PLMN-Identity'},true},
-%% {'SystemInformationBlockType1_cellAccessRelatedInformation_plmn-IdentityList_SEQOF',{'PLMN-Identity'},false},
-%% {'SystemInformationBlockType1_cellAccessRelatedInformation_plmn-IdentityList_SEQOF',{'PLMN-Identity'},true}],
-%% {'TrackingAreaCode'},
-%% {'CellIdentity'},
-%% false,
-%% true,
-%% true,
-%% true
-%% },
-%% {'SystemInformationBlockType1_cellSelectionInfo',-50},
-%% 24,
-%% [{'SystemInformationBlockType1_schedulinInformation_SEQOF',
-%% {'SystemInformationBlockType1_schedulinInformation_SEQOF_si-MessageType'},
-%% ms320,
-%% {'SystemInformationBlockType1_schedulinInformation_SEQOF_sib-MappingInfo'}}],
-%% 0
-%% }
-%% }
-%% }
-%% };
-%% eutra2(result) ->
-%% %% 55 5C A5 E0
-%% <<85,92,165,224>>.
-
-
-
-%% compare([H|T1],[H|T2],Acc) ->
-%% compare(T1,T2,[H|Acc]);
-%% compare([],[],_Acc) ->
-%% ok;
-%% compare(L1,L2,Acc) ->
-%% {miss_match,L1,L2,lists:reverse(Acc)}.
-
-
diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl
index 4ee7e48a67..8fed341600 100644
--- a/lib/common_test/src/cth_log_redirect.erl
+++ b/lib/common_test/src/cth_log_redirect.erl
@@ -34,13 +34,15 @@
%% Event handler Callbacks
-export([init/1,
handle_event/2, handle_call/2, handle_info/2,
- terminate/1]).
+ terminate/1, terminate/2, code_change/3]).
%% Other
-export([handle_remote_events/1]).
-include("ct.hrl").
+-behaviour(gen_event).
+
-record(eh_state, {log_func,
curr_suite,
curr_group,
@@ -184,10 +186,13 @@ handle_call({handle_remote_events,Bool}, State) ->
handle_call(_Query, _State) ->
{error, bad_query}.
-terminate(_State) ->
+terminate(_) ->
error_logger:delete_report_handler(?MODULE),
[].
+terminate(_Arg, _State) ->
+ ok.
+
tag_event(Event) ->
{calendar:local_time(), Event}.
@@ -236,3 +241,6 @@ format_header(#eh_state{curr_suite = Suite,
curr_func = TC}) ->
io_lib:format("System report during ~w:~w/1 in ~w",
[Suite,TC,Group]).
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
diff --git a/lib/common_test/test/common_test.cover b/lib/common_test/test/common_test.cover
index 3aa49623e7..87d00c420f 100644
--- a/lib/common_test/test/common_test.cover
+++ b/lib/common_test/test/common_test.cover
@@ -4,7 +4,6 @@
test_server,
test_server_ctrl,
test_server_gl,
- test_server_h,
test_server_io,
test_server_node,
test_server_sup]}]}.
diff --git a/lib/common_test/test/ct_pre_post_test_io_SUITE.erl b/lib/common_test/test/ct_pre_post_test_io_SUITE.erl
index 84341a0b99..5de1ecc2bd 100644
--- a/lib/common_test/test/ct_pre_post_test_io_SUITE.erl
+++ b/lib/common_test/test/ct_pre_post_test_io_SUITE.erl
@@ -89,28 +89,31 @@ pre_post_io(Config) ->
%%!--------------------------------------------------------------------
spawn(fun() ->
+ ct:pal("CONTROLLER: Started!", []),
%% --- test run 1 ---
- ct:sleep(3000),
- ct_test_support:ct_rpc({cth_log_redirect,
- handle_remote_events,
- [true]}, Config),
- ct:sleep(2000),
- io:format(user, "Starting test run!~n", []),
- ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config),
- ct:sleep(6000),
- io:format(user, "Finishing off!~n", []),
- ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config),
+ timer:sleep(3000),
+ ct:pal("CONTROLLER: Handle remote events = true", []),
+ ok = ct_test_support:ct_rpc({cth_log_redirect,
+ handle_remote_events,
+ [true]}, Config),
+ timer:sleep(2000),
+ ct:pal("CONTROLLER: Proceeding with test run #1!", []),
+ ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config),
+ timer:sleep(6000),
+ ct:pal("CONTROLLER: Proceeding with shutdown #1!", []),
+ ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config),
%% --- test run 2 ---
- ct:sleep(3000),
- ct_test_support:ct_rpc({cth_log_redirect,
- handle_remote_events,
- [true]}, Config),
- ct:sleep(2000),
- io:format(user, "Starting test run!~n", []),
- ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config),
- ct:sleep(6000),
- io:format(user, "Finishing off!~n", []),
- ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config)
+ timer:sleep(3000),
+ ct:pal("CONTROLLER: Handle remote events = true", []),
+ ok = ct_test_support:ct_rpc({cth_log_redirect,
+ handle_remote_events,
+ [true]}, Config),
+ timer:sleep(2000),
+ ct:pal("CONTROLLER: Proceeding with test run #2!", []),
+ ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config),
+ timer:sleep(6000),
+ ct:pal("CONTROLLER: Proceeding with shutdown #2!", []),
+ ok = ct_test_support:ct_rpc({cth_ctrl,proceed,[]}, Config)
end),
ct_test_support:run(Opts, Config),
Events = ct_test_support:get_events(ERPid, Config),
diff --git a/lib/common_test/test/ct_pre_post_test_io_SUITE_data/cth_ctrl.erl b/lib/common_test/test/ct_pre_post_test_io_SUITE_data/cth_ctrl.erl
index c8c08a5735..2ba991fc61 100644
--- a/lib/common_test/test/ct_pre_post_test_io_SUITE_data/cth_ctrl.erl
+++ b/lib/common_test/test/ct_pre_post_test_io_SUITE_data/cth_ctrl.erl
@@ -28,7 +28,8 @@
%%%===================================================================
proceed() ->
- ?MODULE ! proceed.
+ ?MODULE ! proceed,
+ ok.
%%--------------------------------------------------------------------
%% Hook functions
diff --git a/lib/compiler/src/beam_clean.erl b/lib/compiler/src/beam_clean.erl
index e208ffec1f..9d89e21a4e 100644
--- a/lib/compiler/src/beam_clean.erl
+++ b/lib/compiler/src/beam_clean.erl
@@ -86,7 +86,7 @@ add_to_work_list(F, {Fs,Used}=Sets) ->
false -> {[F|Fs],sets:add_element(F, Used)}
end.
-
+
%%%
%%% Coalesce adjacent labels. Renumber all labels to eliminate gaps.
%%% This cleanup will slightly reduce file size and slightly speed up loading.
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl
index 3b51216a6c..3ec57a67da 100644
--- a/lib/compiler/src/beam_type.erl
+++ b/lib/compiler/src/beam_type.erl
@@ -600,7 +600,7 @@ checkerror_1([], OrigIs) -> OrigIs.
checkerror_2(OrigIs) -> [{set,[],[],fcheckerror}|OrigIs].
-
+
%%% Routines for maintaining a type database. The type database
%%% associates type information with registers.
%%%
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index 70279ab658..48f5135aca 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -530,7 +530,7 @@ valfun_2(I, #vst{current=#st{ct=[[Fail]|_]}}=Vst) when is_integer(Fail) ->
%% Update branched state
valfun_3(I, branch_state(Fail, Vst));
valfun_2(_, _) ->
- error(ambigous_catch_try_state).
+ error(ambiguous_catch_try_state).
%% Handle the remaining floating point instructions here.
%% Floating point.
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 802e3dfa2f..47d446273b 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -1556,7 +1556,7 @@ restore_expand_module([F|Fs]) ->
[F|restore_expand_module(Fs)];
restore_expand_module([]) -> [].
-
+
-spec options() -> 'ok'.
options() ->
@@ -1593,7 +1593,7 @@ help([_|T]) ->
help(_) ->
ok.
-
+
%% compile(AbsFileName, Outfilename, Options)
%% Compile entry point for erl_compile.
diff --git a/lib/compiler/src/core_scan.erl b/lib/compiler/src/core_scan.erl
index 0ca2f57dde..c0dfecd1dc 100644
--- a/lib/compiler/src/core_scan.erl
+++ b/lib/compiler/src/core_scan.erl
@@ -96,7 +96,7 @@ format_error(Other) -> io_lib:write(Other).
string_thing($') -> "atom"; %' stupid emacs
string_thing($") -> "string". %" stupid emacs
-
+
%% Re-entrant pre-scanner.
%%
%% If the input list of characters is insufficient to build a term the
@@ -214,7 +214,7 @@ pre_comment(eof, Sofar, Pos) ->
pre_error(E, Epos, Pos) ->
{error,{Epos,core_scan,E}, Pos}.
-
+
%% scan(CharList, StartPos)
%% This takes a list of characters and tries to tokenise them.
%%
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 1195937d91..01bb8635cd 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -1912,7 +1912,7 @@ new_in_all([Le|Les]) ->
foldl(fun (L, Ns) -> intersection((get_anno(L))#a.ns, Ns) end,
(get_anno(Le))#a.ns, Les);
new_in_all([]) -> [].
-
+
%% The AfterVars are the variables which are used afterwards. We need
%% this to work out which variables are actually exported and used
%% from case/receive. In subblocks/clauses the AfterVars of the block
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index 2b2b8bf550..65f1251099 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -160,8 +160,8 @@ function({#c_var{name={F,Arity}=FA},Body}, St0) ->
io:fwrite("Function: ~w/~w\n", [F,Arity]),
erlang:raise(Class, Error, Stack)
end.
-
-
+
+
%% body(Cexpr, Sub, State) -> {Kexpr,[PreKepxr],State}.
%% Do the main sequence of a body. A body ends in an atomic value or
%% values. Must check if vector first so do expr.
@@ -834,7 +834,7 @@ last([_|T]) -> last(T).
first([_]) -> [];
first([H|T]) -> [H|first(T)].
-
+
%% This code implements the algorithm for an optimizing compiler for
%% pattern matching given "The Implementation of Functional
%% Programming Languages" by Simon Peyton Jones. The code is much
@@ -1428,7 +1428,7 @@ arg_val(Arg, C) ->
{set_kanno(S, []),U,T,Fs}
end
end.
-
+
%% ubody_used_vars(Expr, State) -> [UsedVar]
%% Return all used variables for the body sequence. Much more
%% efficient than using ubody/3 if the body contains nested letrecs.
diff --git a/lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/lists1.erl b/lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/lists1.erl
index 0214983c11..db84ee5fc8 100644
--- a/lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/lists1.erl
+++ b/lib/debugger/test/dbg_ui_SUITE_data/manual_data/src/lists1.erl
@@ -236,7 +236,7 @@ flatlength([H|T], L) when list(H) ->
flatlength([H|T], L) ->
flatlength(T, L + 1);
flatlength([], L) -> L.
-
+
%% keymember(Key, Index, [Tuple])
%% keysearch(Key, Index, [Tuple])
%% keydelete(Key, Index, [Tuple])
@@ -298,7 +298,7 @@ keymap(Fun, ExtraArgs, Index, [Tup|Tail]) ->
[setelement(Index, Tup, apply(Fun, [element(Index, Tup)|ExtraArgs]))|
keymap(Fun, ExtraArgs, Index, Tail)];
keymap( _, _ , _, []) -> [].
-
+
%% all(Predicate, List)
%% any(Predicate, List)
%% map(Function, List)
diff --git a/lib/debugger/test/int_SUITE_data/lists1.erl b/lib/debugger/test/int_SUITE_data/lists1.erl
index 0214983c11..db84ee5fc8 100644
--- a/lib/debugger/test/int_SUITE_data/lists1.erl
+++ b/lib/debugger/test/int_SUITE_data/lists1.erl
@@ -236,7 +236,7 @@ flatlength([H|T], L) when list(H) ->
flatlength([H|T], L) ->
flatlength(T, L + 1);
flatlength([], L) -> L.
-
+
%% keymember(Key, Index, [Tuple])
%% keysearch(Key, Index, [Tuple])
%% keydelete(Key, Index, [Tuple])
@@ -298,7 +298,7 @@ keymap(Fun, ExtraArgs, Index, [Tup|Tail]) ->
[setelement(Index, Tup, apply(Fun, [element(Index, Tup)|ExtraArgs]))|
keymap(Fun, ExtraArgs, Index, Tail)];
keymap( _, _ , _, []) -> [].
-
+
%% all(Predicate, List)
%% any(Predicate, List)
%% map(Function, List)
diff --git a/lib/debugger/test/int_SUITE_data/my_lists.erl b/lib/debugger/test/int_SUITE_data/my_lists.erl
index 98eb4396e3..f9399b1085 100644
--- a/lib/debugger/test/int_SUITE_data/my_lists.erl
+++ b/lib/debugger/test/int_SUITE_data/my_lists.erl
@@ -237,7 +237,7 @@ flatlength([H|T], L) when list(H) ->
flatlength([H|T], L) ->
flatlength(T, L + 1);
flatlength([], L) -> L.
-
+
%% keymember(Key, Index, [Tuple])
%% keysearch(Key, Index, [Tuple])
%% keydelete(Key, Index, [Tuple])
@@ -299,7 +299,7 @@ keymap(Fun, ExtraArgs, Index, [Tup|Tail]) ->
[setelement(Index, Tup, apply(Fun, [element(Index, Tup)|ExtraArgs]))|
keymap(Fun, ExtraArgs, Index, Tail)];
keymap( _, _ , _, []) -> [].
-
+
%% all(Predicate, List)
%% any(Predicate, List)
%% map(Function, List)
@@ -698,7 +698,7 @@ flatlength_1([H|T], L) when list(H) ->
flatlength_1([H|T], L) ->
flatlength_1(T, L + 1);
flatlength_1([], L) -> L.
-
+
%% keymember(Key, Index, [Tuple])
%% keysearch(Key, Index, [Tuple])
%% keydelete(Key, Index, [Tuple])
@@ -760,7 +760,7 @@ keymap_1(Fun, ExtraArgs, Index, [Tup|Tail]) ->
[setelement(Index, Tup, apply(Fun, [element(Index, Tup)|ExtraArgs]))|
keymap_1(Fun, ExtraArgs, Index, Tail)];
keymap_1( _, _ , _, []) -> [].
-
+
%% all(Predicate, List)
%% any(Predicate, List)
%% map(Function, List)
@@ -1162,7 +1162,7 @@ flatlength_2([H|T], L) when list(H) ->
flatlength_2([H|T], L) ->
flatlength_2(T, L + 1);
flatlength_2([], L) -> L.
-
+
%% keymember_2(Key, Index, [Tuple])
%% keysearch_2(Key, Index, [Tuple])
%% keydelete_2(Key, Index, [Tuple])
@@ -1224,7 +1224,7 @@ keymap_2(Fun, ExtraArgs, Index, [Tup|Tail]) ->
[setelement(Index, Tup, apply(Fun, [element(Index, Tup)|ExtraArgs]))|
keymap_2(Fun, ExtraArgs, Index, Tail)];
keymap_2( _, _ , _, []) -> [].
-
+
%% all_2(Predicate, List)
%% any_2(Predicate, List)
%% map_2(Function, List)
@@ -1624,7 +1624,7 @@ flatlength_3([H|T], L) when list(H) ->
flatlength_3([H|T], L) ->
flatlength_3(T, L + 1);
flatlength_3([], L) -> L.
-
+
%% keymember_3(Key, Index, [Tuple])
%% keysearch_3(Key, Index, [Tuple])
%% keydelete_3(Key, Index, [Tuple])
@@ -1686,7 +1686,7 @@ keymap_3(Fun, ExtraArgs, Index, [Tup|Tail]) ->
[setelement(Index, Tup, apply(Fun, [element(Index, Tup)|ExtraArgs]))|
keymap_3(Fun, ExtraArgs, Index, Tail)];
keymap_3( _, _ , _, []) -> [].
-
+
%% all_3(Predicate, List)
%% any_3(Predicate, List)
%% map_3(Function, List)
diff --git a/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_clean.erl b/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_clean.erl
index 04225e9bd0..4fc4e89ce9 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_clean.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_clean.erl
@@ -80,7 +80,7 @@ add_to_work_list(F, {Fs,Used}=Sets) ->
false -> {[F|Fs],sets:add_element(F, Used)}
end.
-
+
%%%
%%% Coalesce adjacent labels. Renumber all labels to eliminate gaps.
%%% This cleanup will slightly reduce file size and slightly speed up loading.
diff --git a/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_type.erl b/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_type.erl
index d2ac3fcd99..f59cc897d6 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_type.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/beam_type.erl
@@ -456,7 +456,7 @@ are_live_regs_determinable([{'%live',_}|_]) -> true;
are_live_regs_determinable([_|Is]) -> are_live_regs_determinable(Is);
are_live_regs_determinable([]) -> false.
-
+
%%% Routines for maintaining a type database. The type database
%%% associates type information with registers.
%%%
diff --git a/lib/dialyzer/test/options1_SUITE_data/src/compiler/compile.erl b/lib/dialyzer/test/options1_SUITE_data/src/compiler/compile.erl
index 2b6d14e300..9b56d384ab 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/compile.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/compile.erl
@@ -990,7 +990,7 @@ listing(LFun, Ext, St) ->
Es = [{Lfile,[{none,compile,write_error}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end.
-
+
options() ->
help(standard_passes()).
@@ -1022,7 +1022,7 @@ help([_|T]) ->
help(_) ->
ok.
-
+
%% compile(AbsFileName, Outfilename, Options)
%% Compile entry point for erl_compile.
diff --git a/lib/dialyzer/test/options1_SUITE_data/src/compiler/core_scan.erl b/lib/dialyzer/test/options1_SUITE_data/src/compiler/core_scan.erl
index f4e609bf5b..879af3efea 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/core_scan.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/core_scan.erl
@@ -123,7 +123,7 @@ format_error(Other) -> io_lib:write(Other).
string_thing($') -> "atom";
string_thing($") -> "string".
-
+
%% Re-entrant pre-scanner.
%%
%% If the input list of characters is insufficient to build a term the
@@ -241,7 +241,7 @@ pre_comment(eof, Sofar, Pos) ->
pre_error(E, Epos, Pos) ->
{error,{Epos,core_scan,E}, Pos}.
-
+
%% scan(CharList, StartPos)
%% This takes a list of characters and tries to tokenise them.
%%
diff --git a/lib/dialyzer/test/options1_SUITE_data/src/compiler/sys_pre_expand.erl b/lib/dialyzer/test/options1_SUITE_data/src/compiler/sys_pre_expand.erl
index 41b7cb248d..590cc682c9 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/sys_pre_expand.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/sys_pre_expand.erl
@@ -647,7 +647,7 @@ new_fun_name(#expand{func=F,arity=A,fcount=I}=St) ->
++ "-fun-" ++ integer_to_list(I) ++ "-",
{list_to_atom(Name),St#expand{fcount=I+1}}.
-
+
%% normalise_fields([RecDef]) -> [Field].
%% Normalise the field definitions to always have a default value. If
%% none has been given then use 'undefined'.
@@ -881,7 +881,7 @@ bin_expand_strings(Es) ->
end, Es1, S);
(E, Es1) -> [E|Es1]
end, [], Es).
-
+
%% new_var_name(State) -> {VarName,State}.
new_var_name(St) ->
diff --git a/lib/dialyzer/test/options1_SUITE_data/src/compiler/v3_core.erl b/lib/dialyzer/test/options1_SUITE_data/src/compiler/v3_core.erl
index c96837ab5e..45a8bc4ad9 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/v3_core.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/v3_core.erl
@@ -1127,7 +1127,7 @@ new_in_all([Le|Les]) ->
foldl(fun (L, Ns) -> intersection((core_lib:get_anno(L))#a.ns, Ns) end,
(core_lib:get_anno(Le))#a.ns, Les);
new_in_all([]) -> [].
-
+
%% The AfterVars are the variables which are used afterwards. We need
%% this to work out which variables are actually exported and used
%% from case/receive. In subblocks/clauses the AfterVars of the block
diff --git a/lib/dialyzer/test/options1_SUITE_data/src/compiler/v3_kernel.erl b/lib/dialyzer/test/options1_SUITE_data/src/compiler/v3_kernel.erl
index d7c3e1add9..ecba19b1d1 100644
--- a/lib/dialyzer/test/options1_SUITE_data/src/compiler/v3_kernel.erl
+++ b/lib/dialyzer/test/options1_SUITE_data/src/compiler/v3_kernel.erl
@@ -129,7 +129,7 @@ function(#c_def{anno=Af,name=#c_fname{id=F,arity=Arity},val=Body}, St0) ->
%%B1 = B0, St3 = St2, %Null second pass
{#k_fdef{anno=#k{us=[],ns=[],a=Af ++ Ab},
func=F,arity=Arity,vars=Kvs,body=B1},St3}.
-
+
%% body(Cexpr, Sub, State) -> {Kexpr,[PreKepxr],State}.
%% Do the main sequence of a body. A body ends in an atomic value or
%% values. Must check if vector first so do expr.
@@ -719,7 +719,7 @@ last([_|T]) -> last(T).
first([_]) -> [];
first([H|T]) -> [H|first(T)].
-
+
%% This code implements the algorithm for an optimizing compiler for
%% pattern matching given "The Implementation of Functional
%% Programming Languages" by Simon Peyton Jones. The code is much
@@ -1143,7 +1143,7 @@ arg_val(Arg) ->
#k_bin_end{} -> 0;
#k_binary{} -> 0
end.
-
+
%% ubody(Expr, Break, State) -> {Expr,[UsedVar],State}.
%% Tag the body sequence with its used variables. These bodies
%% either end with a #k_break{}, or with #k_return{} or an expression
diff --git a/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_cgi.erl b/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_cgi.erl
index d3f67eb77a..8c91b6f430 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_cgi.erl
+++ b/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_cgi.erl
@@ -338,7 +338,7 @@ exec_script(false,Info,Script,_AfterScript,_RequestURI) ->
%%
proxy(#mod{config_db = ConfigDb} = Info, Port) ->
- Timeout = httpd_util:lookup(ConfigDb, cgi_timeout, ?DEFAULT_CGI_TIMEOUT),
+ Timeout = httpd_util:lookup(ConfigDb, script_timeout, ?DEFAULT_CGI_TIMEOUT),
proxy(Info, Port, 0, undefined,[], Timeout).
proxy(Info, Port, Size, StatusCode, AccResponse, Timeout) ->
diff --git a/lib/dialyzer/test/small_SUITE_data/results/trec b/lib/dialyzer/test/small_SUITE_data/results/trec
index 01ccc63761..b95df1e6ef 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/trec
+++ b/lib/dialyzer/test/small_SUITE_data/results/trec
@@ -1,7 +1,7 @@
-trec.erl:26: Function test/0 has no local return
-trec.erl:27: The call trec:mk_foo_loc(42,any()) will never return since it differs in the 1st argument from the success typing arguments: ('undefined',atom())
-trec.erl:29: Function mk_foo_loc/2 has no local return
-trec.erl:30: Record construction violates the declared type for #foo{} since variable A cannot be of type atom()
-trec.erl:36: Function mk_foo_exp/2 has no local return
-trec.erl:37: Record construction violates the declared type for #foo{} since variable A cannot be of type atom()
+trec.erl:28: Function test/0 has no local return
+trec.erl:29: The call trec:mk_foo_loc(42,any()) will never return since it differs in the 1st argument from the success typing arguments: ('undefined',atom())
+trec.erl:31: Function mk_foo_loc/2 has no local return
+trec.erl:32: Record construction violates the declared type for #foo{} since variable A cannot be of type atom()
+trec.erl:38: Function mk_foo_exp/2 has no local return
+trec.erl:39: Record construction violates the declared type for #foo{} since variable A cannot be of type atom()
diff --git a/lib/dialyzer/test/small_SUITE_data/src/appmon_place.erl b/lib/dialyzer/test/small_SUITE_data/src/appmon_place.erl
index 60ffbe818f..ddb97796fb 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/appmon_place.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/appmon_place.erl
@@ -1,6 +1,6 @@
%%---------------------------------------------------------------------
%% This is added as a test because it was giving a false positive
-%% (function move/4 will nevr be called) due to the strange use of
+%% (function move/4 will never be called) due to the strange use of
%% self-recursive fun construction in placex/3.
%%
%% The analysis was getting confused that the foldl call will never
diff --git a/lib/dialyzer/test/small_SUITE_data/src/contract3.erl b/lib/dialyzer/test/small_SUITE_data/src/contract3.erl
index 5b0bee9694..a6ce91882e 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/contract3.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/contract3.erl
@@ -18,16 +18,23 @@ t(X, Y, Z) ->
(atom()|list()) -> atom().
t1(X) ->
- foo:bar(X).
+ f(X).
-spec t2(atom(), integer()) -> integer();
(atom(), list()) -> atom().
t2(X, Y) ->
- foo:bar(X, Y).
+ g(X, Y).
-spec t3(atom(), integer(), list()) -> integer();
(X, integer(), list()) -> X.
t3(X, Y, Z) ->
X.
+
+%% dummy functions below
+
+f(X) -> X.
+
+g(X, Y) when is_atom(X), is_integer(Y) -> Y;
+g(X, Y) when is_atom(X), is_list(Y) -> X.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/empty_list_infimum.erl b/lib/dialyzer/test/small_SUITE_data/src/empty_list_infimum.erl
index b58fa732cb..3acc5ca065 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/empty_list_infimum.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/empty_list_infimum.erl
@@ -1,6 +1,6 @@
%%
-%% The Original Code is RabbitMQ.
-%%
+%% This is stripped down code from RabbitMQ. It is used to report an
+%% invalid type specification for function list_vhost_permissions/1.
%% The Initial Developer of the Original Code is VMware, Inc.
%%
@@ -38,7 +38,7 @@ vhost_perms_info_keys() ->
-spec list_vhost_permissions(vhost()) -> infos().
list_vhost_permissions(VHostPath) ->
- list_permissions(vhost_perms_info_keys(), rabbit_foo:some_list()).
+ list_permissions(vhost_perms_info_keys(), some_mod:some_function()).
filter_props(Keys, Props) ->
[T || T = {K, _} <- Props, lists:member(K, Keys)].
diff --git a/lib/dialyzer/test/small_SUITE_data/src/gencall.erl b/lib/dialyzer/test/small_SUITE_data/src/gencall.erl
index d2875c9df1..762be55007 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/gencall.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/gencall.erl
@@ -7,6 +7,6 @@
f() ->
gen_server:call(1,2,3),
ets:lookup(1,2,3),
- gencall2:foo(),
+ some_mod:some_function(),
gencall:foo(),
gen_server:handle_cast(1,2).
diff --git a/lib/dialyzer/test/small_SUITE_data/src/maybe_improper.erl b/lib/dialyzer/test/small_SUITE_data/src/maybe_improper.erl
index 1743d81493..6d2a35b7c8 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/maybe_improper.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/maybe_improper.erl
@@ -1,7 +1,18 @@
+%%%========================================================================
+%%% Tests handling of maybe improper lists
+%%%========================================================================
-module(maybe_improper).
--export([s/1]).
+-export([s/1, t/0]).
-spec s(maybe_improper_list(X,Y)) -> {[X], maybe_improper_list(X,Y)}.
-s(A) ->
- lists:split(2,A).
+s(L) ->
+ lists:split(2, L).
+
+%% Having a remote type in the 'tail' of the list crashed dialyzer.
+%% The problem was fixed for R16B03.
+-type t_mil() :: maybe_improper_list(integer(), orddict:orddict()).
+
+-spec t() -> t_mil().
+t() ->
+ [42 | []].
diff --git a/lib/dialyzer/test/small_SUITE_data/src/overloaded1.erl b/lib/dialyzer/test/small_SUITE_data/src/overloaded1.erl
index 0af4f7446f..074a93e2fe 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/overloaded1.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/overloaded1.erl
@@ -1,5 +1,5 @@
%%-----------------------------------------------------------------------------
-%% Test that tests overloaded contratcs.
+%% Test that tests overloaded contracts.
%% In December 2008 it works as far as intersection types are concerned (test1)
%% However, it does NOT work as far as type variables are concerned (test2)
%%-----------------------------------------------------------------------------
@@ -16,13 +16,13 @@ test2() ->
-type mod() :: atom().
--spec foo(ATM, list()) -> {'ok', ATM} | {'error', _} when is_subtype(ATM, mod())
- ; (MFA, list()) -> {'ok', MFA} | {'error', _} when is_subtype(MFA, mfa()).
+-spec foo(ATM, list()) -> {'ok', ATM} | {'error', _} when ATM :: mod()
+ ; (MFA, list()) -> {'ok', MFA} | {'error', _} when MFA :: mfa().
foo(F, _) when is_atom(F) ->
case atom_to_list(F) of
- [42|_] -> {ok, F};
- _Other -> {error, mod:bar(F)}
+ [42|_] -> {ok, F};
+ _Other -> {error, some_mod:some_function()}
end;
foo({M,F,A}, _) ->
case A =:= 0 of
diff --git a/lib/dialyzer/test/small_SUITE_data/src/trec.erl b/lib/dialyzer/test/small_SUITE_data/src/trec.erl
index ba50c3b401..06706162c1 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/trec.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/trec.erl
@@ -18,20 +18,22 @@
%% ('undefined',atom())
%% 3. Function mk_foo_loc/2 has no local return
%%
-%% Arguably, the second warning is not what most users have in mind
-%% when they wrote the type declarations in the 'foo' record, so no
-%% doubt they'll find it confusing. But note that it is also inconsistent!
-%% How come there is a success typing for a function that has no local return?
+%% Arguably, the second warning is not what most users have in mind when
+%% they wrote the type declarations in the 'foo' record, so no doubt
+%% they'll find it confusing. But note that it is also quite confusing!
+%% Many users may be wondering: How come there is a success typing for a
+%% function that has no local return? Running typer on this module
+%% reveals a success typing for this function that is interesting indeed.
%%
test() ->
- mk_foo_loc(42, bar:f()).
+ mk_foo_loc(42, some_mod:some_function()).
mk_foo_loc(A, B) ->
#foo{a = A, b = [A,B]}.
%%
-%% For this function we currently get "has no local return" but we get
-%% no reason; I want us to get a reason.
+%% For this function we used to get a "has no local return" warning
+%% but we got no reason. This has now been fixed.
%%
mk_foo_exp(A, B) when is_integer(A) ->
#foo{a = A, b = [A,B]}.
diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml
index 32082e565d..cf87a13225 100644
--- a/lib/diameter/doc/src/notes.xml
+++ b/lib/diameter/doc/src/notes.xml
@@ -42,6 +42,36 @@ first.</p>
<!-- ===================================================================== -->
+<section><title>diameter 1.4.4</title>
+
+ <section><title>Known Bugs and Problems</title>
+ <list>
+ <item>
+ <p>
+ Fix setting of End-to-End and Hop-by-Hop Identifiers in
+ outgoing DWA.</p>
+ <p>
+ Broken by OTP-11184, which caused the identifiers to be
+ set anew, discarding the values from the incoming DWR.</p>
+ <p>
+ Own Id: OTP-11367</p>
+ </item>
+ <item>
+ <p>
+ Fix handling of 5014, DIAMETER_INVALID_AVP_LENGTH.</p>
+ <p>
+ The error was detected as 5004,
+ DIAMETER_INVALID_AVP_VALUE, for some Diameter types, in
+ which case an AVP length that pointed past the end of a
+ message resulted in encode failure.</p>
+ <p>
+ Own Id: OTP-11395</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>diameter 1.4.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl
index 1d647b8c87..0de4d53973 100644
--- a/lib/diameter/src/base/diameter_codec.erl
+++ b/lib/diameter/src/base/diameter_codec.erl
@@ -477,8 +477,11 @@ split_head(<<Code:32, 1:1, M:1, P:1, _:5, Len:24, V:32, _/bitstring>>) ->
split_head(<<Code:32, 0:1, M:1, P:1, _:5, Len:24, _/bitstring>>) ->
{Code, undefined, M, P, Len, 8};
-split_head(Bin) ->
- ?THROW({5014, #diameter_avp{data = Bin}}).
+%% Header is truncated: pack_avp/1 will pad to the minimum header
+%% length.
+split_head(B)
+ when is_bitstring(B) ->
+ ?THROW({5014, #diameter_avp{data = B}}).
%% 3588:
%%
@@ -523,9 +526,8 @@ split_data(_, _, _) ->
%% split_data/4
split_data(Bin, HdrLen, Len, Pad) ->
- <<_:HdrLen/binary, T/bitstring>> = Bin,
- case T of
- <<Data:Len/binary, _:Pad/binary, Rest/bitstring>> ->
+ case Bin of
+ <<_:HdrLen/binary, Data:Len/binary, _:Pad/binary, Rest/bitstring>> ->
{Data, Rest};
_ ->
invalid_avp_length()
@@ -573,15 +575,15 @@ pack_avp(#diameter_avp{data = {Dict, Name, Value}} = A) ->
{Name, Type} = Dict:avp_name(Code, Vid),
pack_avp(A#diameter_avp{data = {Hdr, {Type, Value}}});
-pack_avp(#diameter_avp{code = undefined, data = Bin})
- when is_binary(Bin) ->
+pack_avp(#diameter_avp{code = undefined, data = B})
+ when is_bitstring(B) ->
%% Reset the AVP Length of an AVP Header resulting from a 5014
%% error. The RFC doesn't explicitly say to do this but the
%% receiver can't correctly extract this and following AVP's
%% without a correct length. On the downside, the header doesn't
%% reveal if the received header has been padded.
- Pad = 8*header_length(Bin) - bit_size(Bin),
- Len = size(<<H:5/binary, _:24, T/binary>> = <<Bin/bitstring, 0:Pad>>),
+ Pad = 8*header_length(B) - bit_size(B),
+ Len = size(<<H:5/binary, _:24, T/binary>> = <<B/bitstring, 0:Pad>>),
<<H/binary, Len:24, T/binary>>;
%% ... or as an iolist.
diff --git a/lib/diameter/src/base/diameter_types.erl b/lib/diameter/src/base/diameter_types.erl
index 8c07e84777..ca3338be5f 100644
--- a/lib/diameter/src/base/diameter_types.erl
+++ b/lib/diameter/src/base/diameter_types.erl
@@ -92,6 +92,9 @@
when is_binary(Bin) ->
binary_to_list(Bin);
+'OctetString'(decode, B) ->
+ ?INVALID_LENGTH(B);
+
'OctetString'(encode = M, zero) ->
'OctetString'(M, []);
@@ -255,9 +258,7 @@
2 == A, 16 == size(B) ->
list_to_tuple([N || <<N:A/unit:8>> <= B]);
-'Address'(decode, <<A:16, _/binary>> = B)
- when 1 == A;
- 2 == A ->
+'Address'(decode, B) ->
?INVALID_LENGTH(B);
'Address'(encode, T) ->
@@ -278,7 +279,10 @@
<<_,_/binary>> = 'OctetString'(M, X);
'DiameterIdentity'(decode = M, <<_,_/binary>> = X) ->
- 'OctetString'(M, X).
+ 'OctetString'(M, X);
+
+'DiameterIdentity'(decode, X) ->
+ ?INVALID_LENGTH(X).
%% --------------------
@@ -286,6 +290,9 @@
when is_binary(Bin) ->
scan_uri(Bin);
+'DiameterURI'(decode, B) ->
+ ?INVALID_LENGTH(B);
+
%% The minimal DiameterURI is "aaa://x", 7 characters.
'DiameterURI'(encode = M, zero) ->
'OctetString'(M, lists:duplicate(0,7));
@@ -330,9 +337,13 @@
%% --------------------
-'UTF8String'(decode, Bin) ->
+'UTF8String'(decode, Bin)
+ when is_binary(Bin) ->
tl([0|_] = unicode:characters_to_list([0, Bin])); %% assert list return
+'UTF8String'(decode, B) ->
+ ?INVALID_LENGTH(B);
+
'UTF8String'(encode = M, zero) ->
'UTF8String'(M, []);
diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl
index 7e75801718..127a647b89 100644
--- a/lib/diameter/src/base/diameter_watchdog.erl
+++ b/lib/diameter/src/base/diameter_watchdog.erl
@@ -461,15 +461,28 @@ eraser(Key) ->
%% encode/3
-encode(Msg, Mask, Dict) ->
+encode(dwr = M, Dict0, Mask) ->
+ Msg = getr(M),
Seq = diameter_session:sequence(Mask),
Hdr = #diameter_header{version = ?DIAMETER_VERSION,
end_to_end_id = Seq,
hop_by_hop_id = Seq},
Pkt = #diameter_packet{header = Hdr,
msg = Msg},
- #diameter_packet{bin = Bin} = diameter_codec:encode(Dict, Pkt),
- Bin.
+ #diameter_packet{bin = Bin} = diameter_codec:encode(Dict0, Pkt),
+ Bin;
+
+
+encode(dwa, Dict0, #diameter_packet{header = H, transport_data = TD}
+ = ReqPkt) ->
+ AnsPkt = #diameter_packet{header
+ = H#diameter_header{is_request = false,
+ is_error = undefined,
+ is_retransmitted = false},
+ msg = dwa(ReqPkt),
+ transport_data = TD},
+
+ diameter_codec:encode(Dict0, AnsPkt).
%% okay/3
@@ -527,7 +540,7 @@ send_watchdog(#watchdog{pending = false,
dictionary = Dict0,
sequence = Mask}
= S) ->
- send(TPid, {send, encode(getr(dwr), Mask, Dict0)}),
+ send(TPid, {send, encode(dwr, Dict0, Mask)}),
?LOG(send, 'DWR'),
S#watchdog{pending = true}.
@@ -546,9 +559,8 @@ recv(Name, Pkt, S) ->
%% rcv/3
rcv('DWR', Pkt, #watchdog{transport = TPid,
- dictionary = Dict0,
- sequence = Mask}) ->
- send(TPid, {send, encode(dwa(Pkt), Mask, Dict0)}),
+ dictionary = Dict0}) ->
+ send(TPid, {send, encode(dwa, Dict0, Pkt)}),
?LOG(send, 'DWA');
rcv(N, _, _)
diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src
index c6828e6705..76fb54e03a 100644
--- a/lib/diameter/src/diameter.appup.src
+++ b/lib/diameter/src/diameter.appup.src
@@ -35,7 +35,10 @@
{load_module, diameter_config},
{load_module, diameter_service},
{load_module, diameter_peer_fsm},
- {load_module, diameter_watchdog}]}
+ {load_module, diameter_watchdog}]},
+ {"1.4.3", [{load_module, diameter_watchdog}, %% R16B02
+ {load_module, diameter_codec},
+ {load_module, diameter_types}]}
],
[
{"0.9", [{restart_application, diameter}]},
@@ -49,6 +52,9 @@
{"1.4", [{restart_application, diameter}]},
{"1.4.1", [{restart_application, diameter}]},
{"1.4.1.1", [{restart_application, diameter}]},
- {"1.4.2", [{restart_application, diameter}]}
+ {"1.4.2", [{restart_application, diameter}]},
+ {"1.4.3", [{load_module, diameter_types},
+ {load_module, diameter_codec},
+ {load_module, diameter_watchdog}]}
]
}.
diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk
index e003fe76b9..023c5307b2 100644
--- a/lib/diameter/vsn.mk
+++ b/lib/diameter/vsn.mk
@@ -18,5 +18,5 @@
# %CopyrightEnd%
APPLICATION = diameter
-DIAMETER_VSN = 1.4.3
+DIAMETER_VSN = 1.4.4
APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)
diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml
index 30767abd7e..5b81716543 100644
--- a/lib/eldap/doc/src/eldap.xml
+++ b/lib/eldap/doc/src/eldap.xml
@@ -35,6 +35,7 @@
<p>References:</p>
<list type="bulleted">
<item> <p>RFC 4510 - RFC 4519</p> </item>
+ <item> <p>RFC 2830</p> </item>
</list>
<p>The above publications can be found at <url href="http://www.ietf.org">IETF</url>.
</p>
@@ -87,6 +88,38 @@ filter() See present/1, substrings/2,
</desc>
</func>
<func>
+ <name>start_tls(Handle, Options) -> ok | {error,Error}</name>
+ <fsummary>Upgrade a connection to TLS.</fsummary>
+ <desc>
+ <p>Same as start_tls(Handle, Options, infinity)</p>
+ </desc>
+ </func>
+ <func>
+ <name>start_tls(Handle, Options, Timeout) -> ok | {error,Error}</name>
+ <fsummary>Upgrade a connection to TLS.</fsummary>
+ <type>
+ <v>Handle = handle()</v>
+ <v>Options = ssl:ssl_options()</v>
+ <v>Timeout = inifinity | positive_integer()</v>
+ </type>
+ <desc>
+ <p>Upgrade the connection associated with <c>Handle</c> to a tls connection if possible.</p>
+ <p>The upgrade is done in two phases: first the server is asked for permission to upgrade. Second, if the request is acknowledged, the upgrade is performed.</p>
+ <p>Error responese from phase one will not affect the current encryption state of the connection. Those responses are:</p>
+ <taglist>
+ <tag><c>tls_already_started</c></tag>
+ <item>The connection is already encrypted. The connection is not affected.</item>
+ <tag><c>{response,ResponseFromServer}</c></tag>
+ <item>The upgrade was refused by the LDAP server. The <c>ResponseFromServer</c> is an atom delivered byt the LDAP server explained in section 2.3 of rfc 2830. The connection is not affected, so it is still un-encrypted.</item>
+ </taglist>
+ <p>Errors in the seconde phase will however end the connection:</p>
+ <taglist>
+ <tag><c>Error</c></tag>
+ <item>Any error responded from ssl:connect/3</item>
+ </taglist>
+ </desc>
+ </func>
+ <func>
<name>simple_bind(Handle, Dn, Password) -> ok | {error, Reason}</name>
<fsummary>Authenticate the connection.</fsummary>
<type>
diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl
index d11f904996..af5bf94c97 100644
--- a/lib/eldap/src/eldap.erl
+++ b/lib/eldap/src/eldap.erl
@@ -6,10 +6,12 @@
%%% draft-ietf-asid-ldap-c-api-00.txt
%%%
%%% Copyright (c) 2010 Torbjorn Tornkvist
+%%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
%%% See MIT-LICENSE at the top dir for licensing information.
%%% --------------------------------------------------------------------
-vc('$Id$ ').
-export([open/1,open/2,simple_bind/3,controlling_process/2,
+ start_tls/2, start_tls/3,
baseObject/0,singleLevel/0,wholeSubtree/0,close/1,
equalityMatch/2,greaterOrEqual/2,lessOrEqual/2,
approxMatch/2,search/2,substrings/2,present/1,
@@ -36,14 +38,16 @@
host, % Host running LDAP server
port = ?LDAP_PORT, % The LDAP server port
fd, % Socket filedescriptor.
+ prev_fd, % Socket that was upgraded by start_tls
binddn = "", % Name of the entry to bind as
passwd, % Password for (above) entry
id = 0, % LDAP Request ID
log, % User provided log function
timeout = infinity, % Request timeout
anon_auth = false, % Allow anonymous authentication
- use_tls = false, % LDAP/LDAPS
- tls_opts = [] % ssl:ssloptsion()
+ ldaps = false, % LDAP/LDAPS
+ using_tls = false, % true if LDAPS or START_TLS executed
+ tls_opts = [] % ssl:ssloption()
}).
%%% For debug purposes
@@ -77,6 +81,16 @@ open(Hosts, Opts) when is_list(Hosts), is_list(Opts) ->
recv(Pid).
%%% --------------------------------------------------------------------
+%%% Upgrade an existing connection to tls
+%%% --------------------------------------------------------------------
+start_tls(Handle, TlsOptions) ->
+ start_tls(Handle, TlsOptions, infinity).
+
+start_tls(Handle, TlsOptions, Timeout) ->
+ send(Handle, {start_tls,TlsOptions,Timeout}),
+ recv(Handle).
+
+%%% --------------------------------------------------------------------
%%% Shutdown connection (and process) asynchronous.
%%% --------------------------------------------------------------------
@@ -351,11 +365,11 @@ parse_args([{anon_auth, true}|T], Cpid, Data) ->
parse_args([{anon_auth, _}|T], Cpid, Data) ->
parse_args(T, Cpid, Data);
parse_args([{ssl, true}|T], Cpid, Data) ->
- parse_args(T, Cpid, Data#eldap{use_tls = true});
+ parse_args(T, Cpid, Data#eldap{ldaps = true, using_tls=true});
parse_args([{ssl, _}|T], Cpid, Data) ->
parse_args(T, Cpid, Data);
parse_args([{sslopts, Opts}|T], Cpid, Data) when is_list(Opts) ->
- parse_args(T, Cpid, Data#eldap{use_tls = true, tls_opts = Opts ++ Data#eldap.tls_opts});
+ parse_args(T, Cpid, Data#eldap{ldaps = true, using_tls=true, tls_opts = Opts ++ Data#eldap.tls_opts});
parse_args([{sslopts, _}|T], Cpid, Data) ->
parse_args(T, Cpid, Data);
parse_args([{log, F}|T], Cpid, Data) when is_function(F) ->
@@ -386,11 +400,10 @@ try_connect([Host|Hosts], Data) ->
try_connect([],_) ->
{error,"connect failed"}.
-do_connect(Host, Data, Opts) when Data#eldap.use_tls == false ->
+do_connect(Host, Data, Opts) when Data#eldap.ldaps == false ->
gen_tcp:connect(Host, Data#eldap.port, Opts, Data#eldap.timeout);
-do_connect(Host, Data, Opts) when Data#eldap.use_tls == true ->
- SslOpts = [{verify,0} | Opts ++ Data#eldap.tls_opts],
- ssl:connect(Host, Data#eldap.port, SslOpts).
+do_connect(Host, Data, Opts) when Data#eldap.ldaps == true ->
+ ssl:connect(Host, Data#eldap.port, Opts++Data#eldap.tls_opts).
loop(Cpid, Data) ->
receive
@@ -431,6 +444,11 @@ loop(Cpid, Data) ->
?PRINT("New Cpid is: ~p~n",[NewCpid]),
?MODULE:loop(NewCpid, Data);
+ {From, {start_tls,TlsOptions,Timeout}} ->
+ {Res,NewData} = do_start_tls(Data, TlsOptions, Timeout),
+ send(From,Res),
+ ?MODULE:loop(Cpid, NewData);
+
{_From, close} ->
unlink(Cpid),
exit(closed);
@@ -445,6 +463,51 @@ loop(Cpid, Data) ->
end.
+
+%%% --------------------------------------------------------------------
+%%% startTLS Request
+%%% --------------------------------------------------------------------
+
+do_start_tls(Data=#eldap{using_tls=true}, _, _) ->
+ {{error,tls_already_started}, Data};
+do_start_tls(Data=#eldap{fd=FD} , TlsOptions, Timeout) ->
+ case catch exec_start_tls(Data) of
+ {ok,NewData} ->
+ case ssl:connect(FD,TlsOptions,Timeout) of
+ {ok, SslSocket} ->
+ {ok, NewData#eldap{prev_fd = FD,
+ fd = SslSocket,
+ using_tls = true
+ }};
+ {error,Error} ->
+ {{error,Error}, Data}
+ end;
+ {error,Error} -> {{error,Error},Data};
+ Else -> {{error,Else},Data}
+ end.
+
+-define(START_TLS_OID, "1.3.6.1.4.1.1466.20037").
+
+exec_start_tls(Data) ->
+ Req = #'ExtendedRequest'{requestName = ?START_TLS_OID},
+ Reply = request(Data#eldap.fd, Data, Data#eldap.id, {extendedReq, Req}),
+ exec_extended_req_reply(Data, Reply).
+
+exec_extended_req_reply(Data, {ok,Msg}) when
+ Msg#'LDAPMessage'.messageID == Data#eldap.id ->
+ case Msg#'LDAPMessage'.protocolOp of
+ {extendedResp, Result} ->
+ case Result#'ExtendedResponse'.resultCode of
+ success ->
+ {ok,Data};
+ Error ->
+ {error, {response,Error}}
+ end;
+ Other -> {error, Other}
+ end;
+exec_extended_req_reply(_, Error) ->
+ {error, Error}.
+
%%% --------------------------------------------------------------------
%%% bindRequest
%%% --------------------------------------------------------------------
@@ -686,14 +749,14 @@ send_request(S, Data, ID, Request) ->
Else -> Else
end.
-do_send(S, Data, Bytes) when Data#eldap.use_tls == false ->
+do_send(S, Data, Bytes) when Data#eldap.using_tls == false ->
gen_tcp:send(S, Bytes);
-do_send(S, Data, Bytes) when Data#eldap.use_tls == true ->
+do_send(S, Data, Bytes) when Data#eldap.using_tls == true ->
ssl:send(S, Bytes).
-do_recv(S, #eldap{use_tls=false, timeout=Timeout}, Len) ->
+do_recv(S, #eldap{using_tls=false, timeout=Timeout}, Len) ->
gen_tcp:recv(S, Len, Timeout);
-do_recv(S, #eldap{use_tls=true, timeout=Timeout}, Len) ->
+do_recv(S, #eldap{using_tls=true, timeout=Timeout}, Len) ->
ssl:recv(S, Len, Timeout).
recv_response(S, Data) ->
@@ -801,7 +864,7 @@ recv(From) ->
{error, {internal_error, Reason}}
end.
-ldap_closed_p(Data, Emsg) when Data#eldap.use_tls == true ->
+ldap_closed_p(Data, Emsg) when Data#eldap.using_tls == true ->
%% Check if the SSL socket seems to be alive or not
case catch ssl:sockname(Data#eldap.fd) of
{error, _} ->
diff --git a/lib/eldap/test/README b/lib/eldap/test/README
new file mode 100644
index 0000000000..8774db1504
--- /dev/null
+++ b/lib/eldap/test/README
@@ -0,0 +1,36 @@
+
+This works for me on Ubuntu.
+
+To run thoose test you need
+ 1) some certificates
+ 2) a running ldap server, for example OpenLDAPs slapd. See http://www.openldap.org/doc/admin24
+
+1)-------
+To generate certificates:
+erl
+> make_certs:all("/dev/null", "eldap_basic_SUITE_data/certs").
+
+2)-------
+To start slapd:
+ sudo slapd -f $ERL_TOP/lib/eldap/test/ldap_server/slapd.conf -F /tmp/slapd/slapd.d -h "ldap://localhost:9876 ldaps://localhost:9877"
+
+This will however not work, since slapd is guarded by apparmor that checks that slapd does not access other than allowed files...
+
+To make a local extension of alowed operations:
+ sudo emacs /etc/apparmor.d/local/usr.sbin.slapd
+
+and, after the change (yes, at least on Ubuntu it is right to edit ../local/.. but run with an other file) :
+
+ sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.slapd
+
+
+The local file looks like this for me:
+
+# Site-specific additions and overrides for usr.sbin.slapd.
+# For more details, please see /etc/apparmor.d/local/README.
+
+/etc/pkcs11/** r,
+/usr/lib/x86_64-linux-gnu/** rm,
+
+/ldisk/hans_otp/otp/lib/eldap/test/** rw,
+/tmp/slapd/** rwk,
diff --git a/lib/eldap/test/eldap.cfg b/lib/eldap/test/eldap.cfg
new file mode 100644
index 0000000000..3a24afa067
--- /dev/null
+++ b/lib/eldap/test/eldap.cfg
@@ -0,0 +1 @@
+{eldap_server,{"localhost",389}}.
diff --git a/lib/eldap/test/eldap_basic_SUITE.erl b/lib/eldap/test/eldap_basic_SUITE.erl
index c7e3052b29..127d753b92 100644
--- a/lib/eldap/test/eldap_basic_SUITE.erl
+++ b/lib/eldap/test/eldap_basic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012. All Rights Reserved.
+%% Copyright Ericsson AB 2012-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
@@ -27,39 +27,36 @@
-define(TIMEOUT, 120000). % 2 min
-init_per_suite(Config0) ->
- {{EldapHost,Port}, Config1} =
- case catch ct:get_config(eldap_server, undefined) of
- undefined -> %% Dev test only
- Server = {"localhost", 9876},
- {Server, [{eldap_server, {"localhost", 9876}}|Config0]};
- {'EXIT', _} -> %% Dev test only
- Server = {"localhost", 9876},
- {Server, [{eldap_server, {"localhost", 9876}}|Config0]};
- Server ->
- {Server, [{eldap_server, Server}|Config0]}
- end,
- %% Add path for this test run
+init_per_suite(Config) ->
+ ssl:start(),
+ chk_config(ldap_server, {"localhost",9876},
+ chk_config(ldaps_server, {"localhost",9877},
+ Config)).
+
+end_per_suite(_Config) ->
+ ok.
+
+init_per_testcase(_TestCase, Config0) ->
+ {EldapHost,Port} = proplists:get_value(ldap_server,Config0),
try
- {ok, Handle} = eldap:open([EldapHost], [{port, Port}]),
+ {ok, Handle} = eldap:open([EldapHost], [{port,Port}]),
ok = eldap:simple_bind(Handle, "cn=Manager,dc=ericsson,dc=se", "hejsan"),
{ok, MyHost} = inet:gethostname(),
Path = "dc="++MyHost++",dc=ericsson,dc=se",
- Config = [{eldap_path,Path}|Config1],
eldap:add(Handle,"dc=ericsson,dc=se",
[{"objectclass", ["dcObject", "organization"]},
{"dc", ["ericsson"]}, {"o", ["Testing"]}]),
eldap:add(Handle,Path,
[{"objectclass", ["dcObject", "organization"]},
{"dc", [MyHost]}, {"o", ["Test machine"]}]),
- Config
+ [{eldap_path,Path}|Config0]
catch error:{badmatch,Error} ->
io:format("Eldap init error ~p~n ~p~n",[Error, erlang:get_stacktrace()]),
- {skip, lists:flatten(io_lib:format("Ldap init failed with host ~p", [EldapHost]))}
+ {skip, lists:flatten(io_lib:format("Ldap init failed with host ~p:~p. Error=~p", [EldapHost,Port,Error]))}
end.
-end_per_suite(Config) ->
- %% Cleanup everything
- {EHost, Port} = proplists:get_value(eldap_server, Config),
+
+end_per_testcase(_TestCase, Config) ->
+ {EHost, Port} = proplists:get_value(ldap_server, Config),
Path = proplists:get_value(eldap_path, Config),
{ok, H} = eldap:open([EHost], [{port, Port}]),
ok = eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan"),
@@ -71,16 +68,20 @@ end_per_suite(Config) ->
[ok = eldap:delete(H, Entry) || {eldap_entry, Entry, _} <- Entries];
_ -> ignore
end,
- ok.
-init_per_testcase(_TestCase, Config) -> Config.
-end_per_testcase(_TestCase, _Config) -> ok.
+ ok.
%% suite() ->
all() ->
[app,
- api].
+ api,
+ ssl_api,
+ start_tls,
+ tls_operations,
+ start_tls_twice,
+ start_tls_on_ssl
+ ].
app(doc) -> "Test that the eldap app file is ok";
app(suite) -> [];
@@ -90,21 +91,89 @@ app(Config) when is_list(Config) ->
api(doc) -> "Basic test that all api functions works as expected";
api(suite) -> [];
api(Config) ->
- {Host,Port} = proplists:get_value(eldap_server, Config),
+ {Host,Port} = proplists:get_value(ldap_server, Config),
{ok, H} = eldap:open([Host], [{port,Port}]),
%% {ok, H} = eldap:open([Host], [{port,Port+1}, {ssl, true}]),
+ do_api_checks(H, Config),
+ eldap:close(H),
+ ok.
+
+
+ssl_api(doc) -> "Basic test that all api functions works as expected";
+ssl_api(suite) -> [];
+ssl_api(Config) ->
+ {Host,Port} = proplists:get_value(ldaps_server, Config),
+ {ok, H} = eldap:open([Host], [{port,Port}, {ssl,true}]),
+ do_api_checks(H, Config),
+ eldap:close(H),
+ ok.
+
+
+start_tls(doc) -> "Test that an existing (tcp) connection can be upgraded to tls";
+start_tls(suite) -> [];
+start_tls(Config) ->
+ {Host,Port} = proplists:get_value(ldap_server, Config),
+ {ok, H} = eldap:open([Host], [{port,Port}]),
+ ok = eldap:start_tls(H, [
+ {keyfile, filename:join([proplists:get_value(data_dir,Config),
+ "certs/client/key.pem"])}
+ ]),
+ eldap:close(H).
+
+
+tls_operations(doc) -> "Test that an upgraded connection is usable for ldap stuff";
+tls_operations(suite) -> [];
+tls_operations(Config) ->
+ {Host,Port} = proplists:get_value(ldap_server, Config),
+ {ok, H} = eldap:open([Host], [{port,Port}]),
+ ok = eldap:start_tls(H, [
+ {keyfile, filename:join([proplists:get_value(data_dir,Config),
+ "certs/client/key.pem"])}
+ ]),
+ do_api_checks(H, Config),
+ eldap:close(H).
+
+start_tls_twice(doc) -> "Test that start_tls on an already upgraded connection fails";
+start_tls_twice(suite) -> [];
+start_tls_twice(Config) ->
+ {Host,Port} = proplists:get_value(ldap_server, Config),
+ {ok, H} = eldap:open([Host], [{port,Port}]),
+ ok = eldap:start_tls(H, []),
+ {error,tls_already_started} = eldap:start_tls(H, []),
+ do_api_checks(H, Config),
+ eldap:close(H).
+
+
+start_tls_on_ssl(doc) -> "Test that start_tls on an ldaps connection fails";
+start_tls_on_ssl(suite) -> [];
+start_tls_on_ssl(Config) ->
+ {Host,Port} = proplists:get_value(ldaps_server, Config),
+ {ok, H} = eldap:open([Host], [{port,Port}, {ssl,true}]),
+ {error,tls_already_started} = eldap:start_tls(H, []),
+ do_api_checks(H, Config),
+ eldap:close(H).
+
+
+%%%--------------------------------------------------------------------------------
+chk_config(Key, Default, Config) ->
+ case catch ct:get_config(ldap_server, undefined) of
+ undefined -> [{Key,Default} | Config ];
+ {'EXIT',_} -> [{Key,Default} | Config ];
+ Value -> [{Key,Value} | Config]
+ end.
+
+
+
+do_api_checks(H, Config) ->
BasePath = proplists:get_value(eldap_path, Config),
+
All = fun(Where) ->
eldap:search(H, #eldap_search{base=Where,
filter=eldap:present("objectclass"),
scope= eldap:wholeSubtree()})
end,
- Search = fun(Filter) ->
- eldap:search(H, #eldap_search{base=BasePath,
- filter=Filter,
- scope=eldap:singleLevel()})
- end,
- {ok, #eldap_search_result{entries=[_]}} = All(BasePath),
+ {ok, #eldap_search_result{entries=[_XYZ]}} = All(BasePath),
+%% ct:log("XYZ=~p",[_XYZ]),
{error, noSuchObject} = All("cn=Bar,"++BasePath),
{error, _} = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath,
@@ -112,52 +181,67 @@ api(Config) ->
{"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]),
eldap:simple_bind(H, "cn=Manager,dc=ericsson,dc=se", "hejsan"),
- %% Add
+ chk_add(H, BasePath),
+ {ok,FB} = chk_search(H, BasePath),
+ chk_modify(H, FB),
+ chk_delete(H, BasePath),
+ chk_modify_dn(H, FB).
+
+
+chk_add(H, BasePath) ->
ok = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath,
[{"objectclass", ["person"]},
{"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]),
+ {error, entryAlreadyExists} = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath,
+ [{"objectclass", ["person"]},
+ {"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]),
ok = eldap:add(H, "cn=Foo Bar," ++ BasePath,
[{"objectclass", ["person"]},
{"cn", ["Foo Bar"]}, {"sn", ["Bar"]}, {"telephoneNumber", ["555-1232", "555-5432"]}]),
ok = eldap:add(H, "ou=Team," ++ BasePath,
[{"objectclass", ["organizationalUnit"]},
- {"ou", ["Team"]}]),
+ {"ou", ["Team"]}]).
- %% Search
+chk_search(H, BasePath) ->
+ Search = fun(Filter) ->
+ eldap:search(H, #eldap_search{base=BasePath,
+ filter=Filter,
+ scope=eldap:singleLevel()})
+ end,
JJSR = {ok, #eldap_search_result{entries=[#eldap_entry{}]}} = Search(eldap:equalityMatch("sn", "Jonsson")),
JJSR = Search(eldap:substrings("sn", [{any, "ss"}])),
FBSR = {ok, #eldap_search_result{entries=[#eldap_entry{object_name=FB}]}} =
Search(eldap:substrings("sn", [{any, "a"}])),
FBSR = Search(eldap:substrings("sn", [{initial, "B"}])),
FBSR = Search(eldap:substrings("sn", [{final, "r"}])),
-
F_AND = eldap:'and'([eldap:present("objectclass"), eldap:present("ou")]),
{ok, #eldap_search_result{entries=[#eldap_entry{}]}} = Search(F_AND),
F_NOT = eldap:'and'([eldap:present("objectclass"), eldap:'not'(eldap:present("ou"))]),
{ok, #eldap_search_result{entries=[#eldap_entry{}, #eldap_entry{}]}} = Search(F_NOT),
+ {ok,FB}. %% FIXME
- %% MODIFY
+chk_modify(H, FB) ->
Mod = [eldap:mod_replace("telephoneNumber", ["555-12345"]),
eldap:mod_add("description", ["Nice guy"])],
%% io:format("MOD ~p ~p ~n",[FB, Mod]),
ok = eldap:modify(H, FB, Mod),
%% DELETE ATTR
- ok = eldap:modify(H, FB, [eldap:mod_delete("telephoneNumber", [])]),
+ ok = eldap:modify(H, FB, [eldap:mod_delete("telephoneNumber", [])]).
- %% DELETE
+
+chk_delete(H, BasePath) ->
{error, entryAlreadyExists} = eldap:add(H, "cn=Jonas Jonsson," ++ BasePath,
[{"objectclass", ["person"]},
{"cn", ["Jonas Jonsson"]}, {"sn", ["Jonsson"]}]),
ok = eldap:delete(H, "cn=Jonas Jonsson," ++ BasePath),
- {error, noSuchObject} = eldap:delete(H, "cn=Jonas Jonsson," ++ BasePath),
+ {error, noSuchObject} = eldap:delete(H, "cn=Jonas Jonsson," ++ BasePath).
- %% MODIFY_DN
- ok = eldap:modify_dn(H, FB, "cn=Niclas Andre", true, ""),
- %%io:format("Res ~p~n ~p~n",[R, All(BasePath)]),
+chk_modify_dn(H, FB) ->
+ ok = eldap:modify_dn(H, FB, "cn=Niclas Andre", true, "").
+ %%io:format("Res ~p~n ~p~n",[R, All(BasePath)]).
- eldap:close(H),
- ok.
+%%%----------------
add(H, Attr, Value, Path0, Attrs, Class) ->
Path = case Path0 of
[] -> Attr ++ "=" ++ Value;
diff --git a/lib/eldap/test/eldap_basic_SUITE_data/certs/README b/lib/eldap/test/eldap_basic_SUITE_data/certs/README
new file mode 100644
index 0000000000..a7c8e9dc2e
--- /dev/null
+++ b/lib/eldap/test/eldap_basic_SUITE_data/certs/README
@@ -0,0 +1 @@
+See ../../README
diff --git a/lib/eldap/test/ldap_server/slapd.conf b/lib/eldap/test/ldap_server/slapd.conf
index 87be676d9f..eca298c866 100644
--- a/lib/eldap/test/ldap_server/slapd.conf
+++ b/lib/eldap/test/ldap_server/slapd.conf
@@ -1,14 +1,32 @@
-include /etc/ldap/schema/core.schema
-pidfile /tmp/openldap-data/slapd.pid
-argsfile /tmp/openldap-data/slapd.args
+modulepath /usr/lib/ldap
+moduleload back_bdb.la
+
+# example config file - global configuration section
+include /etc/ldap/schema/core.schema
+referral ldap://root.openldap.org
+access to * by * read
+
+TLSCACertificateFile /ldisk/hans_otp/otp/lib/eldap/test/eldap_basic_SUITE_data/certs/server/cacerts.pem
+TLSCertificateFile /ldisk/hans_otp/otp/lib/eldap/test/eldap_basic_SUITE_data/certs/server/cert.pem
+TLSCertificateKeyFile /ldisk/hans_otp/otp/lib/eldap/test/eldap_basic_SUITE_data/certs/server/keycert.pem
+
database bdb
suffix "dc=ericsson,dc=se"
rootdn "cn=Manager,dc=ericsson,dc=se"
rootpw hejsan
+
# The database must exist before running slapd
-directory /tmp/openldap-data
+directory /tmp/slapd/openldap-data-ericsson.se
+
# Indices to maintain
index objectClass eq
-# URI "ldap://0.0.0.0:9876 ldaps://0.0.0.0:9870"
-# servers/slapd/slapd -d 255 -h "ldap://0.0.0.0:9876 ldaps://0.0.0.0:9870" -f /ldisk/dgud/src/otp/lib/eldap/test/ldap_server/slapd.conf \ No newline at end of file
+access to attrs=userPassword
+ by self write
+ by anonymous auth
+ by dn.base="cn=Manager,dc=ericsson,dc=se" write
+ by * none
+access to *
+ by self write
+ by dn.base="cn=Manager,dc=ericsson,dc=se" write
+ by * read
diff --git a/lib/eldap/test/make_certs.erl b/lib/eldap/test/make_certs.erl
new file mode 100644
index 0000000000..f963af180d
--- /dev/null
+++ b/lib/eldap/test/make_certs.erl
@@ -0,0 +1,313 @@
+%%
+%% %CopyrightBegin%
+%%
+%% 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
+%% 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(make_certs).
+
+-export([all/2]).
+
+-record(dn, {commonName,
+ organizationalUnitName = "Erlang OTP",
+ organizationName = "Ericsson AB",
+ localityName = "Stockholm",
+ countryName = "SE",
+ emailAddress = "[email protected]"}).
+
+all(DataDir, PrivDir) ->
+ OpenSSLCmd = "openssl",
+ create_rnd(DataDir, PrivDir), % For all requests
+ rootCA(PrivDir, OpenSSLCmd, "erlangCA"),
+ intermediateCA(PrivDir, OpenSSLCmd, "otpCA", "erlangCA"),
+ endusers(PrivDir, OpenSSLCmd, "otpCA", ["client", "server"]),
+ collect_certs(PrivDir, ["erlangCA", "otpCA"], ["client", "server"]),
+ %% Create keycert files
+ SDir = filename:join([PrivDir, "server"]),
+ SC = filename:join([SDir, "cert.pem"]),
+ SK = filename:join([SDir, "key.pem"]),
+ SKC = filename:join([SDir, "keycert.pem"]),
+ append_files([SK, SC], SKC),
+ CDir = filename:join([PrivDir, "client"]),
+ CC = filename:join([CDir, "cert.pem"]),
+ CK = filename:join([CDir, "key.pem"]),
+ CKC = filename:join([CDir, "keycert.pem"]),
+ append_files([CK, CC], CKC),
+ remove_rnd(PrivDir).
+
+append_files(FileNames, ResultFileName) ->
+ {ok, ResultFile} = file:open(ResultFileName, [write]),
+ do_append_files(FileNames, ResultFile).
+
+do_append_files([], RF) ->
+ ok = file:close(RF);
+do_append_files([F|Fs], RF) ->
+ {ok, Data} = file:read_file(F),
+ ok = file:write(RF, Data),
+ do_append_files(Fs, RF).
+
+rootCA(Root, OpenSSLCmd, Name) ->
+ create_ca_dir(Root, Name, ca_cnf(Name)),
+ DN = #dn{commonName = Name},
+ create_self_signed_cert(Root, OpenSSLCmd, Name, req_cnf(DN)),
+ ok.
+
+intermediateCA(Root, OpenSSLCmd, CA, ParentCA) ->
+ CA = "otpCA",
+ create_ca_dir(Root, CA, ca_cnf(CA)),
+ CARoot = filename:join([Root, CA]),
+ DN = #dn{commonName = CA},
+ CnfFile = filename:join([CARoot, "req.cnf"]),
+ file:write_file(CnfFile, req_cnf(DN)),
+ KeyFile = filename:join([CARoot, "private", "key.pem"]),
+ ReqFile = filename:join([CARoot, "req.pem"]),
+ create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile),
+ CertFile = filename:join([CARoot, "cert.pem"]),
+ sign_req(Root, OpenSSLCmd, ParentCA, "ca_cert", ReqFile, CertFile).
+
+endusers(Root, OpenSSLCmd, CA, Users) ->
+ lists:foreach(fun(User) -> enduser(Root, OpenSSLCmd, CA, User) end, Users).
+
+enduser(Root, OpenSSLCmd, CA, User) ->
+ UsrRoot = filename:join([Root, User]),
+ file:make_dir(UsrRoot),
+ CnfFile = filename:join([UsrRoot, "req.cnf"]),
+ DN = #dn{commonName = User},
+ file:write_file(CnfFile, req_cnf(DN)),
+ KeyFile = filename:join([UsrRoot, "key.pem"]),
+ ReqFile = filename:join([UsrRoot, "req.pem"]),
+ create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile),
+ CertFileAllUsage = filename:join([UsrRoot, "cert.pem"]),
+ sign_req(Root, OpenSSLCmd, CA, "user_cert", ReqFile, CertFileAllUsage),
+ CertFileDigitalSigOnly = filename:join([UsrRoot, "digital_signature_only_cert.pem"]),
+ sign_req(Root, OpenSSLCmd, CA, "user_cert_digital_signature_only", ReqFile, CertFileDigitalSigOnly).
+
+collect_certs(Root, CAs, Users) ->
+ Bins = lists:foldr(
+ fun(CA, Acc) ->
+ File = filename:join([Root, CA, "cert.pem"]),
+ {ok, Bin} = file:read_file(File),
+ [Bin, "\n" | Acc]
+ end, [], CAs),
+ lists:foreach(
+ fun(User) ->
+ File = filename:join([Root, User, "cacerts.pem"]),
+ file:write_file(File, Bins)
+ end, Users).
+
+create_self_signed_cert(Root, OpenSSLCmd, CAName, Cnf) ->
+ CARoot = filename:join([Root, CAName]),
+ CnfFile = filename:join([CARoot, "req.cnf"]),
+ file:write_file(CnfFile, Cnf),
+ KeyFile = filename:join([CARoot, "private", "key.pem"]),
+ CertFile = filename:join([CARoot, "cert.pem"]),
+ Cmd = [OpenSSLCmd, " req"
+ " -new"
+ " -x509"
+ " -config ", CnfFile,
+ " -keyout ", KeyFile,
+ " -out ", CertFile],
+ Env = [{"ROOTDIR", Root}],
+ cmd(Cmd, Env),
+ fix_key_file(OpenSSLCmd, KeyFile).
+
+% openssl 1.0 generates key files in pkcs8 format by default and we don't handle this format
+fix_key_file(OpenSSLCmd, KeyFile) ->
+ KeyFileTmp = KeyFile ++ ".tmp",
+ Cmd = [OpenSSLCmd, " rsa",
+ " -in ",
+ KeyFile,
+ " -out ",
+ KeyFileTmp],
+ cmd(Cmd, []),
+ ok = file:rename(KeyFileTmp, KeyFile).
+
+create_ca_dir(Root, CAName, Cnf) ->
+ CARoot = filename:join([Root, CAName]),
+ file:make_dir(CARoot),
+ create_dirs(CARoot, ["certs", "crl", "newcerts", "private"]),
+ create_rnd(Root, filename:join([CAName, "private"])),
+ create_files(CARoot, [{"serial", "01\n"},
+ {"index.txt", ""},
+ {"ca.cnf", Cnf}]).
+
+create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile) ->
+ Cmd = [OpenSSLCmd, " req"
+ " -new"
+ " -config ", CnfFile,
+ " -keyout ", KeyFile,
+ " -out ", ReqFile],
+ Env = [{"ROOTDIR", Root}],
+ cmd(Cmd, Env),
+ fix_key_file(OpenSSLCmd, KeyFile).
+
+sign_req(Root, OpenSSLCmd, CA, CertType, ReqFile, CertFile) ->
+ CACnfFile = filename:join([Root, CA, "ca.cnf"]),
+ Cmd = [OpenSSLCmd, " ca"
+ " -batch"
+ " -notext"
+ " -config ", CACnfFile,
+ " -extensions ", CertType,
+ " -in ", ReqFile,
+ " -out ", CertFile],
+ Env = [{"ROOTDIR", Root}],
+ cmd(Cmd, Env).
+
+%%
+%% Misc
+%%
+
+create_dirs(Root, Dirs) ->
+ lists:foreach(fun(Dir) ->
+ file:make_dir(filename:join([Root, Dir])) end,
+ Dirs).
+
+create_files(Root, NameContents) ->
+ lists:foreach(
+ fun({Name, Contents}) ->
+ file:write_file(filename:join([Root, Name]), Contents) end,
+ NameContents).
+
+create_rnd(FromDir, ToDir) ->
+ From = filename:join([FromDir, "RAND"]),
+ To = filename:join([ToDir, "RAND"]),
+ file:copy(From, To).
+
+remove_rnd(Dir) ->
+ File = filename:join([Dir, "RAND"]),
+ file:delete(File).
+
+cmd(Cmd, Env) ->
+ FCmd = lists:flatten(Cmd),
+ Port = open_port({spawn, FCmd}, [stream, eof, exit_status, stderr_to_stdout,
+ {env, Env}]),
+ eval_cmd(Port).
+
+eval_cmd(Port) ->
+ receive
+ {Port, {data, _}} ->
+ eval_cmd(Port);
+ {Port, eof} ->
+ ok
+ end,
+ receive
+ {Port, {exit_status, Status}} when Status /= 0 ->
+ %% io:fwrite("exit status: ~w~n", [Status]),
+ exit({eval_cmd, Status})
+ after 0 ->
+ ok
+ end.
+
+%%
+%% Contents of configuration files
+%%
+
+req_cnf(DN) ->
+ ["# Purpose: Configuration for requests (end users and CAs)."
+ "\n"
+ "ROOTDIR = $ENV::ROOTDIR\n"
+ "\n"
+
+ "[req]\n"
+ "input_password = secret\n"
+ "output_password = secret\n"
+ "default_bits = 1024\n"
+ "RANDFILE = $ROOTDIR/RAND\n"
+ "encrypt_key = no\n"
+ "default_md = sha1\n"
+ "#string_mask = pkix\n"
+ "x509_extensions = ca_ext\n"
+ "prompt = no\n"
+ "distinguished_name= name\n"
+ "\n"
+
+ "[name]\n"
+ "commonName = ", DN#dn.commonName, "\n"
+ "organizationalUnitName = ", DN#dn.organizationalUnitName, "\n"
+ "organizationName = ", DN#dn.organizationName, "\n"
+ "localityName = ", DN#dn.localityName, "\n"
+ "countryName = ", DN#dn.countryName, "\n"
+ "emailAddress = ", DN#dn.emailAddress, "\n"
+ "\n"
+
+ "[ca_ext]\n"
+ "basicConstraints = critical, CA:true\n"
+ "keyUsage = cRLSign, keyCertSign\n"
+ "subjectKeyIdentifier = hash\n"
+ "subjectAltName = email:copy\n"].
+
+
+ca_cnf(CA) ->
+ ["# Purpose: Configuration for CAs.\n"
+ "\n"
+ "ROOTDIR = $ENV::ROOTDIR\n"
+ "default_ca = ca\n"
+ "\n"
+
+ "[ca]\n"
+ "dir = $ROOTDIR/", CA, "\n"
+ "certs = $dir/certs\n"
+ "crl_dir = $dir/crl\n"
+ "database = $dir/index.txt\n"
+ "new_certs_dir = $dir/newcerts\n"
+ "certificate = $dir/cert.pem\n"
+ "serial = $dir/serial\n"
+ "crl = $dir/crl.pem\n"
+ "private_key = $dir/private/key.pem\n"
+ "RANDFILE = $dir/private/RAND\n"
+ "\n"
+ "x509_extensions = user_cert\n"
+ "unique_subject = no\n"
+ "default_days = 3600\n"
+ "default_md = sha1\n"
+ "preserve = no\n"
+ "policy = policy_match\n"
+ "\n"
+
+ "[policy_match]\n"
+ "commonName = supplied\n"
+ "organizationalUnitName = optional\n"
+ "organizationName = match\n"
+ "countryName = match\n"
+ "localityName = match\n"
+ "emailAddress = supplied\n"
+ "\n"
+
+ "[user_cert]\n"
+ "basicConstraints = CA:false\n"
+ "keyUsage = nonRepudiation, digitalSignature, keyEncipherment\n"
+ "subjectKeyIdentifier = hash\n"
+ "authorityKeyIdentifier = keyid,issuer:always\n"
+ "subjectAltName = email:copy\n"
+ "issuerAltName = issuer:copy\n"
+ "\n"
+
+ "[user_cert_digital_signature_only]\n"
+ "basicConstraints = CA:false\n"
+ "keyUsage = digitalSignature\n"
+ "subjectKeyIdentifier = hash\n"
+ "authorityKeyIdentifier = keyid,issuer:always\n"
+ "subjectAltName = email:copy\n"
+ "issuerAltName = issuer:copy\n"
+ "\n"
+
+ "[ca_cert]\n"
+ "basicConstraints = critical,CA:true\n"
+ "keyUsage = cRLSign, keyCertSign\n"
+ "subjectKeyIdentifier = hash\n"
+ "authorityKeyIdentifier = keyid:always,issuer:always\n"
+ "subjectAltName = email:copy\n"
+ "issuerAltName = issuer:copy\n"].
diff --git a/lib/erl_docgen/priv/css/otp_doc.css b/lib/erl_docgen/priv/css/otp_doc.css
index c56de378f4..d6641aad4b 100644
--- a/lib/erl_docgen/priv/css/otp_doc.css
+++ b/lib/erl_docgen/priv/css/otp_doc.css
@@ -63,8 +63,8 @@ a:visited { color: blue; text-decoration: none }
margin: 15px; /* Magins for inner DIV inside each DIV (to provide padding) */
}
-span.bold_code { font-family: Courier, monospace; font-weight: bold }
-span.code { font-family: Courier, monospace; font-weight: normal }
+.bold_code { font-family: Courier, monospace; font-weight: bold }
+code { font-family: Courier, monospace; font-weight: normal }
.note, .warning {
border: solid black 1px;
@@ -108,3 +108,122 @@ pre { font-family: Courier, monospace; font-weight: normal }
.REFTYPES { margin-left: 8mm }
footer { }
+pre {
+ padding:5px;
+ display:block;
+ background-color:#EEE;
+ border:1px solid #CCC;
+ border-radius:3px;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+}
+
+pre code,pre .subst,pre .tag .title,pre .lisp .title,pre .clojure .built_in,pre .nginx .title{
+ color:black
+}
+
+pre .string,pre .title,pre .constant,pre .parent,pre .tag .value,pre .rules .value,pre .rules .value .number,pre .preprocessor,pre .ruby .symbol,pre .ruby .symbol .string,pre .aggregate,pre .template_tag,pre .django .variable,pre .smalltalk .class,pre .addition,pre .flow,pre .stream,pre .bash .variable,pre .apache .tag,pre .apache .cbracket,pre .tex .command,pre .tex .special,pre .erlang_repl .function_or_atom,pre .markdown .header{
+ color:#800;
+}
+
+pre .comment,pre .annotation,pre .template_comment,pre .diff .header,pre .chunk,pre .markdown .blockquote{
+ color:#888;
+}
+
+pre .number,pre .date,pre .regexp,pre .literal,pre .smalltalk .symbol,pre .smalltalk .char,pre .go .constant,pre .change,pre .markdown .bullet,pre .markdown .link_url{
+ color:#000;
+}
+
+pre .label,pre .javadoc,pre .ruby .string,pre .decorator,pre .filter .argument,pre .localvars,pre .array,pre .attr_selector,pre .important,pre .pseudo,pre .pi,pre .doctype,pre .deletion,pre .envvar,pre .shebang,pre .apache .sqbracket,pre .nginx .built_in,pre .tex .formula,pre .erlang_repl .reserved,pre .prompt,pre .markdown .link_label,pre .vhdl .attribute,pre .clojure .attribute,pre .coffeescript .property{
+ color:#88F;
+}
+
+pre .keyword,pre .id,pre .phpdoc,pre .title,pre .built_in,pre .aggregate,pre .css .tag,pre .javadoctag,pre .phpdoc,pre .yardoctag,pre .smalltalk .class,pre .winutils,pre .bash .variable,pre .apache .tag,pre .go .typename,pre .tex .command,pre .markdown .strong,pre .request,pre .status, pre .erlang_repl .variable{
+ color:#080;
+}
+
+pre .markdown .emphasis{
+ font-style:italic;
+}
+
+pre .nginx .built_in{
+ font-weight:normal;
+}
+
+pre .coffeescript .javascript,pre .javascript .xml,pre .tex .formula,pre .xml .javascript,pre .xml .vbscript,pre .xml .css,pre .xml .cdata{
+ opacity:.5;
+
+}
+
+.alert {
+ padding: 8px 35px 8px 14px;
+ margin-bottom: 20px;
+ text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ background-color: #fcf8e3;
+ border: 1px solid #fbeed5;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+}
+
+.alert,
+.alert h4 {
+ color: #c09853;
+}
+
+.alert h4 {
+ margin: 0;
+}
+
+.alert .close {
+ position: relative;
+ top: -2px;
+ right: -21px;
+ line-height: 20px;
+}
+
+.alert-success {
+ color: #468847;
+ background-color: #dff0d8;
+ border-color: #d6e9c6;
+}
+
+.alert-success h4 {
+ color: #468847;
+}
+
+.alert-danger,
+.alert-error {
+ color: #b94a48;
+ background-color: #f2dede;
+ border-color: #eed3d7;
+}
+
+.alert-danger h4,
+.alert-error h4 {
+ color: #b94a48;
+}
+
+.alert-info {
+ color: #3a87ad;
+ background-color: #d9edf7;
+ border-color: #bce8f1;
+}
+
+.alert-info h4 {
+ color: #3a87ad;
+}
+
+.alert-block {
+ padding-top: 14px;
+ padding-bottom: 14px;
+}
+
+.alert-block > p,
+.alert-block > ul {
+ margin-bottom: 0;
+}
+
+.alert-block p + p {
+ margin-top: 5px;
+} \ No newline at end of file
diff --git a/lib/erl_docgen/priv/js/flipmenu/Makefile b/lib/erl_docgen/priv/js/flipmenu/Makefile
index 7933752532..40c78c5f7c 100644
--- a/lib/erl_docgen/priv/js/flipmenu/Makefile
+++ b/lib/erl_docgen/priv/js/flipmenu/Makefile
@@ -43,7 +43,8 @@ GIF_FILES = \
flip_static.gif
JS_FILES = \
- flipmenu.js
+ flipmenu.js \
+ jquery-2.0.3.min.js
# ----------------------------------------------------
# FLAGS
diff --git a/lib/erl_docgen/priv/js/flipmenu/flipmenu.js b/lib/erl_docgen/priv/js/flipmenu/flipmenu.js
index 1f70f2509b..7b877a6375 100644
--- a/lib/erl_docgen/priv/js/flipmenu/flipmenu.js
+++ b/lib/erl_docgen/priv/js/flipmenu/flipmenu.js
@@ -350,3 +350,20 @@ cookiePrefix = document.location.pathname + "_";
addEvent(document, "click", toggleFlip);
if (flipInitOnLoad) addEvent(window, "load", initFlip);
+var hljs=new function(){function m(p){return p.replace(/&/gm,"&amp;").replace(/</gm,"&lt;")}function c(r,q,p){return RegExp(q,"m"+(r.cI?"i":"")+(p?"g":""))}function j(r){for(var p=0;p<r.childNodes.length;p++){var q=r.childNodes[p];if(q.nodeName=="CODE"){return q}if(!(q.nodeType==3&&q.nodeValue.match(/\s+/))){break}}}function g(t,s){var r="";for(var q=0;q<t.childNodes.length;q++){if(t.childNodes[q].nodeType==3){var p=t.childNodes[q].nodeValue;if(s){p=p.replace(/\n/g,"")}r+=p}else{if(t.childNodes[q].nodeName=="BR"){r+="\n"}else{r+=g(t.childNodes[q])}}}if(/MSIE [678]/.test(navigator.userAgent)){r=r.replace(/\r/g,"\n")}return r}function a(s){var q=s.className.split(/\s+/);q=q.concat(s.parentNode.className.split(/\s+/));for(var p=0;p<q.length;p++){var r=q[p].replace(/^language-/,"");if(d[r]||r=="no-highlight"){return r}}}function b(p){var q=[];(function(s,t){for(var r=0;r<s.childNodes.length;r++){if(s.childNodes[r].nodeType==3){t+=s.childNodes[r].nodeValue.length}else{if(s.childNodes[r].nodeName=="BR"){t+=1}else{q.push({event:"start",offset:t,node:s.childNodes[r]});t=arguments.callee(s.childNodes[r],t);q.push({event:"stop",offset:t,node:s.childNodes[r]})}}}return t})(p,0);return q}function l(y,z,x){var r=0;var w="";var t=[];function u(){if(y.length&&z.length){if(y[0].offset!=z[0].offset){return(y[0].offset<z[0].offset)?y:z}else{return z[0].event=="start"?y:z}}else{return y.length?y:z}}function s(C){var D="<"+C.nodeName.toLowerCase();for(var A=0;A<C.attributes.length;A++){var B=C.attributes[A];D+=" "+B.nodeName.toLowerCase();if(B.nodeValue!=undefined&&B.nodeValue!=false&&B.nodeValue!=null){D+='="'+m(B.nodeValue)+'"'}}return D+">"}while(y.length||z.length){var v=u().splice(0,1)[0];w+=m(x.substr(r,v.offset-r));r=v.offset;if(v.event=="start"){w+=s(v.node);t.push(v.node)}else{if(v.event=="stop"){var q=t.length;do{q--;var p=t[q];w+=("</"+p.nodeName.toLowerCase()+">")}while(p!=v.node);t.splice(q,1);while(q<t.length){w+=s(t[q]);q++}}}}w+=x.substr(r);return w}function i(){function p(u,t,v){if(u.compiled){return}if(!v){u.bR=c(t,u.b?u.b:"\\B|\\b");if(!u.e&&!u.eW){u.e="\\B|\\b"}if(u.e){u.eR=c(t,u.e)}}if(u.i){u.iR=c(t,u.i)}if(u.r==undefined){u.r=1}if(u.k){u.lR=c(t,u.l||hljs.IR,true)}for(var s in u.k){if(!u.k.hasOwnProperty(s)){continue}if(u.k[s] instanceof Object){u.kG=u.k}else{u.kG={keyword:u.k}}break}if(!u.c){u.c=[]}u.compiled=true;for(var r=0;r<u.c.length;r++){p(u.c[r],t,false)}if(u.starts){p(u.starts,t,false)}}for(var q in d){if(!d.hasOwnProperty(q)){continue}p(d[q].dM,d[q],true)}}function e(J,D){if(!i.called){i();i.called=true}function z(r,M){for(var L=0;L<M.c.length;L++){if(M.c[L].bR.test(r)){return M.c[L]}}}function w(L,r){if(C[L].e&&C[L].eR.test(r)){return 1}if(C[L].eW){var M=w(L-1,r);return M?M+1:0}return 0}function x(r,L){return L.iR&&L.iR.test(r)}function A(O,N){var M=[];for(var L=0;L<O.c.length;L++){M.push(O.c[L].b)}var r=C.length-1;do{if(C[r].e){M.push(C[r].e)}r--}while(C[r+1].eW);if(O.i){M.push(O.i)}return c(N,"("+M.join("|")+")",true)}function s(M,L){var N=C[C.length-1];if(!N.t){N.t=A(N,H)}N.t.lastIndex=L;var r=N.t.exec(M);if(r){return[M.substr(L,r.index-L),r[0],false]}else{return[M.substr(L),"",true]}}function p(O,r){var L=H.cI?r[0].toLowerCase():r[0];for(var N in O.kG){if(!O.kG.hasOwnProperty(N)){continue}var M=O.kG[N].hasOwnProperty(L);if(M){return[N,M]}}return false}function F(M,O){if(!O.k){return m(M)}var N="";var P=0;O.lR.lastIndex=0;var L=O.lR.exec(M);while(L){N+=m(M.substr(P,L.index-P));var r=p(O,L);if(r){t+=r[1];N+='<span class="'+r[0]+'">'+m(L[0])+"</span>"}else{N+=m(L[0])}P=O.lR.lastIndex;L=O.lR.exec(M)}N+=m(M.substr(P,M.length-P));return N}function K(r,M){if(M.sL&&d[M.sL]){var L=e(M.sL,r);t+=L.keyword_count;return L.value}else{return F(r,M)}}function I(M,r){var L=M.cN?'<span class="'+M.cN+'">':"";if(M.rB){q+=L;M.buffer=""}else{if(M.eB){q+=m(r)+L;M.buffer=""}else{q+=L;M.buffer=r}}C.push(M);B+=M.r}function E(O,L,Q){var R=C[C.length-1];if(Q){q+=K(R.buffer+O,R);return false}var M=z(L,R);if(M){q+=K(R.buffer+O,R);I(M,L);return M.rB}var r=w(C.length-1,L);if(r){var N=R.cN?"</span>":"";if(R.rE){q+=K(R.buffer+O,R)+N}else{if(R.eE){q+=K(R.buffer+O,R)+N+m(L)}else{q+=K(R.buffer+O+L,R)+N}}while(r>1){N=C[C.length-2].cN?"</span>":"";q+=N;r--;C.length--}var P=C[C.length-1];C.length--;C[C.length-1].buffer="";if(P.starts){I(P.starts,"")}return R.rE}if(x(L,R)){throw"Illegal"}}var H=d[J];var C=[H.dM];var B=0;var t=0;var q="";try{var v=0;H.dM.buffer="";do{var y=s(D,v);var u=E(y[0],y[1],y[2]);v+=y[0].length;if(!u){v+=y[1].length}}while(!y[2]);if(C.length>1){throw"Illegal"}return{r:B,keyword_count:t,value:q}}catch(G){if(G=="Illegal"){return{r:0,keyword_count:0,value:m(D)}}else{throw G}}}function f(t){var r={keyword_count:0,r:0,value:m(t)};var q=r;for(var p in d){if(!d.hasOwnProperty(p)){continue}var s=e(p,t);s.language=p;if(s.keyword_count+s.r>q.keyword_count+q.r){q=s}if(s.keyword_count+s.r>r.keyword_count+r.r){q=r;r=s}}if(q.language){r.second_best=q}return r}function h(r,q,p){if(q){r=r.replace(/^((<[^>]+>|\t)+)/gm,function(t,w,v,u){return w.replace(/\t/g,q)})}if(p){r=r.replace(/\n/g,"<br>")}return r}function o(u,x,q){var y=g(u,q);var s=a(u);if(s=="no-highlight"){return}if(s){var w=e(s,y)}else{var w=f(y);s=w.language}var p=b(u);if(p.length){var r=document.createElement("pre");r.innerHTML=w.value;w.value=l(p,b(r),y)}w.value=h(w.value,x,q);var t=u.className;if(!t.match("(\\s|^)(language-)?"+s+"(\\s|$)")){t=t?(t+" "+s):s}if(/MSIE [678]/.test(navigator.userAgent)&&u.tagName=="CODE"&&u.parentNode.tagName=="PRE"){var r=u.parentNode;var v=document.createElement("div");v.innerHTML="<pre><code>"+w.value+"</code></pre>";u=v.firstChild.firstChild;v.firstChild.cN=r.cN;r.parentNode.replaceChild(v.firstChild,r)}else{u.innerHTML=w.value}u.className=t;u.result={language:s,kw:w.keyword_count,re:w.r};if(w.second_best){u.second_best={language:w.second_best.language,kw:w.second_best.keyword_count,re:w.second_best.r}}}function k(){if(k.called){return}k.called=true;var r=document.getElementsByTagName("pre");for(var p=0;p<r.length;p++){var q=j(r[p]);if(q){o(q,hljs.tabReplace)}}}function n(){if(window.addEventListener){window.addEventListener("DOMContentLoaded",k,false);window.addEventListener("load",k,false)}else{if(window.attachEvent){window.attachEvent("onload",k)}else{window.onload=k}}}var d={};this.LANGUAGES=d;this.highlight=e;this.highlightAuto=f;this.fixMarkup=h;this.highlightBlock=o;this.initHighlighting=k;this.initHighlightingOnLoad=n;this.IR="[a-zA-Z][a-zA-Z0-9_]*";this.UIR="[a-zA-Z_][a-zA-Z0-9_]*";this.NR="\\b\\d+(\\.\\d+)?";this.CNR="\\b(0x[A-Za-z0-9]+|\\d+(\\.\\d+)?)";this.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|\\.|-|-=|/|/=|:|;|<|<<|<<=|<=|=|==|===|>|>=|>>|>>=|>>>|>>>=|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~";this.BE={b:"\\\\.",r:0};this.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[this.BE],r:0};this.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[this.BE],r:0};this.CLCM={cN:"comment",b:"//",e:"$"};this.CBLCLM={cN:"comment",b:"/\\*",e:"\\*/"};this.HCM={cN:"comment",b:"#",e:"$"};this.NM={cN:"number",b:this.NR,r:0};this.CNM={cN:"number",b:this.CNR,r:0};this.inherit=function(p,s){var r={};for(var q in p){r[q]=p[q]}if(s){for(var q in s){r[q]=s[q]}}return r}}();hljs.LANGUAGES.bash=function(){var d={"true":1,"false":1};var b={cN:"variable",b:"\\$([a-zA-Z0-9_]+)\\b"};var a={cN:"variable",b:"\\$\\{(([^}])|(\\\\}))+\\}",c:[hljs.CNM]};var c={cN:"string",b:'"',e:'"',i:"\\n",c:[hljs.BE,b,a],r:0};var e={cN:"test_condition",b:"",e:"",c:[c,b,a,hljs.CNM],k:{literal:d},r:0};return{dM:{k:{keyword:{"if":1,then:1,"else":1,fi:1,"for":1,"break":1,"continue":1,"while":1,"in":1,"do":1,done:1,echo:1,exit:1,"return":1,set:1,declare:1},literal:d},c:[{cN:"shebang",b:"(#!\\/bin\\/bash)|(#!\\/bin\\/sh)",r:10},hljs.HCM,hljs.CNM,c,b,a,hljs.inherit(e,{b:"\\[ ",e:" \\]",r:0}),hljs.inherit(e,{b:"\\[\\[ ",e:" \\]\\]"})]}}}();hljs.LANGUAGES.erlang=function(){var g="[a-z'][a-zA-Z0-9_']*";var l="("+g+":"+g+"|"+g+")";var d={keyword:{after:1,and:1,andalso:10,band:1,begin:1,bnot:1,bor:1,bsl:1,bzr:1,bxor:1,"case":1,"catch":1,cond:1,div:1,end:1,fun:1,let:1,not:1,of:1,orelse:10,query:1,receive:1,rem:1,"try":1,when:1,xor:1},literal:{"false":1,"true":1}};var j={cN:"comment",b:"%",e:"$",r:0};var c={b:"fun\\s+"+g+"/\\d+"};var m={b:l+"\\(",e:"\\)",rB:true,r:0,c:[{cN:"function_name",b:l,r:0},{b:"\\(",e:"\\)",eW:true,rE:true,r:0}]};var f={cN:"tuple",b:"{",e:"}",r:0};var a={cN:"variable",b:"\\b_([A-Z][A-Za-z0-9_]*)?",r:0};var k={cN:"variable",b:"[A-Z][a-zA-Z0-9_]*",r:0};var h={b:"#",e:"}",i:".",r:0,rB:true,c:[{cN:"record_name",b:"#"+hljs.UIR,r:0},{b:"{",eW:true,r:0}]};var i={k:d,b:"(fun|receive|if|try|case)",e:"end"};i.c=[j,c,hljs.inherit(hljs.ASM,{cN:""}),i,m,hljs.QSM,hljs.CNM,f,a,k,h];var b=[j,c,i,m,hljs.QSM,hljs.CNM,f,a,k,h];m.c[1].c=b;f.c=b;h.c[1].c=b;var e={cN:"params",b:"\\(",e:"\\)",eW:true,c:b};return{dM:{k:d,i:"(</|\\*=|\\+=|-=|/=|/\\*|\\*/|\\(\\*|\\*\\))",c:[{cN:"function",b:"^"+g+"\\(",e:";|\\.",rB:true,c:[e,{cN:"title",b:g},{k:d,b:"->",eW:true,c:b}]},j,{cN:"pp",b:"^-",e:"\\.",r:0,eE:true,rB:true,l:"-"+hljs.IR,k:{"-module":1,"-record":1,"-undef":1,"-export":1,"-ifdef":1,"-ifndef":1,"-author":1,"-copyright":1,"-doc":1,"-vsn":1,"-import":1,"-include":1,"-include_lib":1,"-compile":1,"-define":1,"-else":1,"-endif":1,"-file":1,"-behaviour":1,"-behavior":1},c:[e]},hljs.CNM,hljs.QSM,h,a,k,f]}}}();hljs.LANGUAGES.css=function(){var a={cN:"function",b:hljs.IR+"\\(",e:"\\)",c:[{eW:true,eE:true,c:[hljs.NM,hljs.ASM,hljs.QSM]}]};return{cI:true,dM:{i:"[=/|']",c:[hljs.CBLCLM,{cN:"id",b:"\\#[A-Za-z0-9_-]+"},{cN:"class",b:"\\.[A-Za-z0-9_-]+",r:0},{cN:"attr_selector",b:"\\[",e:"\\]",i:"$"},{cN:"pseudo",b:":(:)?[a-zA-Z0-9\\_\\-\\+\\(\\)\\\"\\']+"},{cN:"at_rule",b:"@(font-face|page)",l:"[a-z-]+",k:{"font-face":1,page:1}},{cN:"at_rule",b:"@",e:"[{;]",eE:true,k:{"import":1,page:1,media:1,charset:1},c:[a,hljs.ASM,hljs.QSM,hljs.NM]},{cN:"tag",b:hljs.IR,r:0},{cN:"rules",b:"{",e:"}",i:"[^\\s]",r:0,c:[hljs.CBLCLM,{cN:"rule",b:"[^\\s]",rB:true,e:";",eW:true,c:[{cN:"attribute",b:"[A-Z\\_\\.\\-]+",e:":",eE:true,i:"[^\\s]",starts:{cN:"value",eW:true,eE:true,c:[a,hljs.NM,hljs.QSM,hljs.ASM,hljs.CBLCLM,{cN:"hexcolor",b:"\\#[0-9A-F]+"},{cN:"important",b:"!important"}]}}]}]}]}}}();hljs.LANGUAGES.erlang_repl={dM:{k:{special_functions:{spawn:10,spawn_link:10,self:2},reserved:{after:1,and:1,andalso:5,band:1,begin:1,bnot:1,bor:1,bsl:1,bsr:1,bxor:1,"case":1,"catch":0,cond:1,div:1,end:1,fun:0,"if":0,let:1,not:0,of:1,or:1,orelse:5,query:1,receive:0,rem:1,"try":0,when:1,xor:1}},c:[{cN:"input_number",b:"^[0-9]+> ",r:10},{cN:"comment",b:"%",e:"$"},hljs.NM,hljs.ASM,hljs.QSM,{cN:"constant",b:"\\?(::)?([A-Z]\\w*(::)?)+"},{cN:"arrow",b:"->"},{cN:"ok",b:"ok"},{cN:"exclamation_mark",b:"!"},{cN:"function_or_atom",b:"(\\b[a-z'][a-zA-Z0-9_']*:[a-z'][a-zA-Z0-9_']*)|(\\b[a-z'][a-zA-Z0-9_']*)",r:0},{cN:"variable",b:"[A-Z][a-zA-Z0-9_']*",r:0}]}};hljs.LANGUAGES.cpp=function(){var b={keyword:{"false":1,"int":1,"float":1,"while":1,"private":1,"char":1,"catch":1,"export":1,virtual:1,operator:2,sizeof:2,dynamic_cast:2,typedef:2,const_cast:2,"const":1,struct:1,"for":1,static_cast:2,union:1,namespace:1,unsigned:1,"long":1,"throw":1,"volatile":2,"static":1,"protected":1,bool:1,template:1,mutable:1,"if":1,"public":1,friend:2,"do":1,"return":1,"goto":1,auto:1,"void":2,"enum":1,"else":1,"break":1,"new":1,extern:1,using:1,"true":1,"class":1,asm:1,"case":1,typeid:1,"short":1,reinterpret_cast:2,"default":1,"double":1,register:1,explicit:1,signed:1,typename:1,"try":1,"this":1,"switch":1,"continue":1,wchar_t:1,inline:1,"delete":1,alignof:1,char16_t:1,char32_t:1,constexpr:1,decltype:1,noexcept:1,nullptr:1,static_assert:1,thread_local:1},built_in:{std:1,string:1,cin:1,cout:1,cerr:1,clog:1,stringstream:1,istringstream:1,ostringstream:1,auto_ptr:1,deque:1,list:1,queue:1,stack:1,vector:1,map:1,set:1,bitset:1,multiset:1,multimap:1,unordered_set:1,unordered_map:1,unordered_multiset:1,unordered_multimap:1,array:1,shared_ptr:1}};var a={cN:"stl_container",b:"\\b(deque|list|queue|stack|vector|map|set|bitset|multiset|multimap|unordered_map|unordered_set|unordered_multiset|unordered_multimap|array)\\s*<",e:">",k:b,r:10};a.c=[a];return{dM:{k:b,i:"</",c:[hljs.CLCM,hljs.CBLCLM,hljs.QSM,{cN:"string",b:"'",e:"[^\\\\]'",i:"[^\\\\][^']"},hljs.CNM,{cN:"preprocessor",b:"#",e:"$"},a]}}}();
+
+$(document).ready(function(){
+ $("pre code").each(function(i, e){
+ if($(e).text().substring(0, 1) == "\n"){
+ $(e).text($(e).text().substring(1, $(e).text().length));
+ }
+ var pattern = new RegExp(/ /g);
+ if(pattern.test($(e).text())){
+ $(e).text($(e).text().replace(/ /g, "\t"));
+ }
+ if($(e).text().substring($(e).text().length-1, $(e).text().length) == "\t"){
+ $(e).text($(e).text().substring(0, $(e).text().length-2));
+ }
+ hljs.highlightBlock(e, '&nbsp;&nbsp;&nbsp;&nbsp;');
+ });
+}); \ No newline at end of file
diff --git a/lib/erl_docgen/priv/js/flipmenu/jquery-2.0.3.min.js b/lib/erl_docgen/priv/js/flipmenu/jquery-2.0.3.min.js
new file mode 100644
index 0000000000..2be209dd22
--- /dev/null
+++ b/lib/erl_docgen/priv/js/flipmenu/jquery-2.0.3.min.js
@@ -0,0 +1,6 @@
+/*! jQuery v2.0.3 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license
+//@ sourceMappingURL=jquery-2.0.3.min.map
+*/
+(function(e,undefined){var t,n,r=typeof undefined,i=e.location,o=e.document,s=o.documentElement,a=e.jQuery,u=e.$,l={},c=[],p="2.0.3",f=c.concat,h=c.push,d=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,x=function(e,n){return new x.fn.init(e,n,t)},b=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:p,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(p+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(t[i]!==undefined)e[r++]=t[i++];return e.length=r,e},grep:function(e,t,n){var r,i=[],o=0,s=e.length;for(n=!!n;s>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,s=j(e),a=[];if(s)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(a[a.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(a[a.length]=r);return f.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;return"string"==typeof t&&(n=e[t],t=e,e=n),x.isFunction(e)?(r=d.call(arguments,2),i=function(){return e.apply(t||this,r.concat(d.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):undefined},access:function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===x.type(n)){i=!0;for(a in n)x.access(e,t,a,n[a],!0,o,s)}else if(r!==undefined&&(i=!0,x.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(x(e),n)})),t))for(;u>a;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o},now:Date.now,swap:function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i}}),x.ready.promise=function(t){return n||(n=x.Deferred(),"complete"===o.readyState?setTimeout(x.ready):(o.addEventListener("DOMContentLoaded",S,!1),e.addEventListener("load",S,!1))),n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function j(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}t=x(o),function(e,undefined){var t,n,r,i,o,s,a,u,l,c,p,f,h,d,g,m,y,v="sizzle"+-new Date,b=e.document,w=0,T=0,C=st(),k=st(),N=st(),E=!1,S=function(e,t){return e===t?(E=!0,0):0},j=typeof undefined,D=1<<31,A={}.hasOwnProperty,L=[],q=L.pop,H=L.push,O=L.push,F=L.slice,P=L.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},R="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",W="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",$=W.replace("w","w#"),B="\\["+M+"*("+W+")"+M+"*(?:([*^$|!~]?=)"+M+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+$+")|)|)"+M+"*\\]",I=":("+W+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+B.replace(3,8)+")*)|.*)\\)|)",z=RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),_=RegExp("^"+M+"*,"+M+"*"),X=RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=RegExp(M+"*[+~]"),Y=RegExp("="+M+"*([^\\]'\"]*)"+M+"*\\]","g"),V=RegExp(I),G=RegExp("^"+$+"$"),J={ID:RegExp("^#("+W+")"),CLASS:RegExp("^\\.("+W+")"),TAG:RegExp("^("+W.replace("w","w*")+")"),ATTR:RegExp("^"+B),PSEUDO:RegExp("^"+I),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:RegExp("^(?:"+R+")$","i"),needsContext:RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Q=/^[^{]+\{\s*\[native \w/,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,Z=/^(?:input|select|textarea|button)$/i,et=/^h\d$/i,tt=/'|\\/g,nt=RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),rt=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:0>r?String.fromCharCode(r+65536):String.fromCharCode(55296|r>>10,56320|1023&r)};try{O.apply(L=F.call(b.childNodes),b.childNodes),L[b.childNodes.length].nodeType}catch(it){O={apply:L.length?function(e,t){H.apply(e,F.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function ot(e,t,r,i){var o,s,a,u,l,f,g,m,x,w;if((t?t.ownerDocument||t:b)!==p&&c(t),t=t||p,r=r||[],!e||"string"!=typeof e)return r;if(1!==(u=t.nodeType)&&9!==u)return[];if(h&&!i){if(o=K.exec(e))if(a=o[1]){if(9===u){if(s=t.getElementById(a),!s||!s.parentNode)return r;if(s.id===a)return r.push(s),r}else if(t.ownerDocument&&(s=t.ownerDocument.getElementById(a))&&y(t,s)&&s.id===a)return r.push(s),r}else{if(o[2])return O.apply(r,t.getElementsByTagName(e)),r;if((a=o[3])&&n.getElementsByClassName&&t.getElementsByClassName)return O.apply(r,t.getElementsByClassName(a)),r}if(n.qsa&&(!d||!d.test(e))){if(m=g=v,x=t,w=9===u&&e,1===u&&"object"!==t.nodeName.toLowerCase()){f=gt(e),(g=t.getAttribute("id"))?m=g.replace(tt,"\\$&"):t.setAttribute("id",m),m="[id='"+m+"'] ",l=f.length;while(l--)f[l]=m+mt(f[l]);x=U.test(e)&&t.parentNode||t,w=f.join(",")}if(w)try{return O.apply(r,x.querySelectorAll(w)),r}catch(T){}finally{g||t.removeAttribute("id")}}}return kt(e.replace(z,"$1"),t,r,i)}function st(){var e=[];function t(n,r){return e.push(n+=" ")>i.cacheLength&&delete t[e.shift()],t[n]=r}return t}function at(e){return e[v]=!0,e}function ut(e){var t=p.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function lt(e,t){var n=e.split("|"),r=e.length;while(r--)i.attrHandle[n[r]]=t}function ct(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function pt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ft(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function ht(e){return at(function(t){return t=+t,at(function(n,r){var i,o=e([],n.length,t),s=o.length;while(s--)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}s=ot.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},n=ot.support={},c=ot.setDocument=function(e){var t=e?e.ownerDocument||e:b,r=t.defaultView;return t!==p&&9===t.nodeType&&t.documentElement?(p=t,f=t.documentElement,h=!s(t),r&&r.attachEvent&&r!==r.top&&r.attachEvent("onbeforeunload",function(){c()}),n.attributes=ut(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ut(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=ut(function(e){return e.innerHTML="<div class='a'></div><div class='a i'></div>",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),n.getById=ut(function(e){return f.appendChild(e).id=v,!t.getElementsByName||!t.getElementsByName(v).length}),n.getById?(i.find.ID=function(e,t){if(typeof t.getElementById!==j&&h){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){return e.getAttribute("id")===t}}):(delete i.find.ID,i.filter.ID=function(e){var t=e.replace(nt,rt);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),i.find.TAG=n.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==j?t.getElementsByTagName(e):undefined}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},i.find.CLASS=n.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==j&&h?t.getElementsByClassName(e):undefined},g=[],d=[],(n.qsa=Q.test(t.querySelectorAll))&&(ut(function(e){e.innerHTML="<select><option selected=''></option></select>",e.querySelectorAll("[selected]").length||d.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll(":checked").length||d.push(":checked")}),ut(function(e){var n=t.createElement("input");n.setAttribute("type","hidden"),e.appendChild(n).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&d.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||d.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),d.push(",.*:")})),(n.matchesSelector=Q.test(m=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&ut(function(e){n.disconnectedMatch=m.call(e,"div"),m.call(e,"[s!='']:x"),g.push("!=",I)}),d=d.length&&RegExp(d.join("|")),g=g.length&&RegExp(g.join("|")),y=Q.test(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},S=f.compareDocumentPosition?function(e,r){if(e===r)return E=!0,0;var i=r.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(r);return i?1&i||!n.sortDetached&&r.compareDocumentPosition(e)===i?e===t||y(b,e)?-1:r===t||y(b,r)?1:l?P.call(l,e)-P.call(l,r):0:4&i?-1:1:e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,o=e.parentNode,s=n.parentNode,a=[e],u=[n];if(e===n)return E=!0,0;if(!o||!s)return e===t?-1:n===t?1:o?-1:s?1:l?P.call(l,e)-P.call(l,n):0;if(o===s)return ct(e,n);r=e;while(r=r.parentNode)a.unshift(r);r=n;while(r=r.parentNode)u.unshift(r);while(a[i]===u[i])i++;return i?ct(a[i],u[i]):a[i]===b?-1:u[i]===b?1:0},t):p},ot.matches=function(e,t){return ot(e,null,null,t)},ot.matchesSelector=function(e,t){if((e.ownerDocument||e)!==p&&c(e),t=t.replace(Y,"='$1']"),!(!n.matchesSelector||!h||g&&g.test(t)||d&&d.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return ot(t,p,null,[e]).length>0},ot.contains=function(e,t){return(e.ownerDocument||e)!==p&&c(e),y(e,t)},ot.attr=function(e,t){(e.ownerDocument||e)!==p&&c(e);var r=i.attrHandle[t.toLowerCase()],o=r&&A.call(i.attrHandle,t.toLowerCase())?r(e,t,!h):undefined;return o===undefined?n.attributes||!h?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null:o},ot.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},ot.uniqueSort=function(e){var t,r=[],i=0,o=0;if(E=!n.detectDuplicates,l=!n.sortStable&&e.slice(0),e.sort(S),E){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return e},o=ot.getText=function(e){var t,n="",r=0,i=e.nodeType;if(i){if(1===i||9===i||11===i){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=o(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r];r++)n+=o(t);return n},i=ot.selectors={cacheLength:50,createPseudo:at,match:J,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(nt,rt),e[3]=(e[4]||e[5]||"").replace(nt,rt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ot.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ot.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return J.CHILD.test(e[0])?null:(e[3]&&e[4]!==undefined?e[2]=e[4]:n&&V.test(n)&&(t=gt(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(nt,rt).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ot.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,p,f,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,y=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){p=t;while(p=p[g])if(a?p.nodeName.toLowerCase()===y:1===p.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&x){c=m[v]||(m[v]={}),l=c[e]||[],h=l[0]===w&&l[1],f=l[0]===w&&l[2],p=h&&m.childNodes[h];while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if(1===p.nodeType&&++f&&p===t){c[e]=[w,h,f];break}}else if(x&&(l=(t[v]||(t[v]={}))[e])&&l[0]===w)f=l[1];else while(p=++h&&p&&p[g]||(f=h=0)||d.pop())if((a?p.nodeName.toLowerCase()===y:1===p.nodeType)&&++f&&(x&&((p[v]||(p[v]={}))[e]=[w,f]),p===t))break;return f-=i,f===r||0===f%r&&f/r>=0}}},PSEUDO:function(e,t){var n,r=i.pseudos[e]||i.setFilters[e.toLowerCase()]||ot.error("unsupported pseudo: "+e);return r[v]?r(t):r.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?at(function(e,n){var i,o=r(e,t),s=o.length;while(s--)i=P.call(e,o[s]),e[i]=!(n[i]=o[s])}):function(e){return r(e,0,n)}):r}},pseudos:{not:at(function(e){var t=[],n=[],r=a(e.replace(z,"$1"));return r[v]?at(function(e,t,n,i){var o,s=r(e,null,i,[]),a=e.length;while(a--)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:at(function(e){return function(t){return ot(e,t).length>0}}),contains:at(function(e){return function(t){return(t.textContent||t.innerText||o(t)).indexOf(e)>-1}}),lang:at(function(e){return G.test(e||"")||ot.error("unsupported lang: "+e),e=e.replace(nt,rt).toLowerCase(),function(t){var n;do if(n=h?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===p.activeElement&&(!p.hasFocus||p.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!i.pseudos.empty(e)},header:function(e){return et.test(e.nodeName)},input:function(e){return Z.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:ht(function(){return[0]}),last:ht(function(e,t){return[t-1]}),eq:ht(function(e,t,n){return[0>n?n+t:n]}),even:ht(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:ht(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:ht(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:ht(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}},i.pseudos.nth=i.pseudos.eq;for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})i.pseudos[t]=pt(t);for(t in{submit:!0,reset:!0})i.pseudos[t]=ft(t);function dt(){}dt.prototype=i.filters=i.pseudos,i.setFilters=new dt;function gt(e,t){var n,r,o,s,a,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);a=e,u=[],l=i.preFilter;while(a){(!n||(r=_.exec(a)))&&(r&&(a=a.slice(r[0].length)||a),u.push(o=[])),n=!1,(r=X.exec(a))&&(n=r.shift(),o.push({value:n,type:r[0].replace(z," ")}),a=a.slice(n.length));for(s in i.filter)!(r=J[s].exec(a))||l[s]&&!(r=l[s](r))||(n=r.shift(),o.push({value:n,type:s,matches:r}),a=a.slice(n.length));if(!n)break}return t?a.length:a?ot.error(e):k(e,u).slice(0)}function mt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function yt(e,t,n){var i=t.dir,o=n&&"parentNode"===i,s=T++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,n,a){var u,l,c,p=w+" "+s;if(a){while(t=t[i])if((1===t.nodeType||o)&&e(t,n,a))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[v]||(t[v]={}),(l=c[i])&&l[0]===p){if((u=l[1])===!0||u===r)return u===!0}else if(l=c[i]=[p],l[1]=e(t,n,a)||r,l[1]===!0)return!0}}function vt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,s=[],a=0,u=e.length,l=null!=t;for(;u>a;a++)(o=e[a])&&(!n||n(o,r,i))&&(s.push(o),l&&t.push(a));return s}function bt(e,t,n,r,i,o){return r&&!r[v]&&(r=bt(r)),i&&!i[v]&&(i=bt(i,o)),at(function(o,s,a,u){var l,c,p,f=[],h=[],d=s.length,g=o||Ct(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:xt(g,f,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=xt(y,h),r(l,[],a,u),c=l.length;while(c--)(p=l[c])&&(y[h[c]]=!(m[h[c]]=p))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(p=y[c])&&l.push(m[c]=p);i(null,y=[],l,u)}c=y.length;while(c--)(p=y[c])&&(l=i?P.call(o,p):f[c])>-1&&(o[l]=!(s[l]=p))}}else y=xt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):O.apply(s,y)})}function wt(e){var t,n,r,o=e.length,s=i.relative[e[0].type],a=s||i.relative[" "],l=s?1:0,c=yt(function(e){return e===t},a,!0),p=yt(function(e){return P.call(t,e)>-1},a,!0),f=[function(e,n,r){return!s&&(r||n!==u)||((t=n).nodeType?c(e,n,r):p(e,n,r))}];for(;o>l;l++)if(n=i.relative[e[l].type])f=[yt(vt(f),n)];else{if(n=i.filter[e[l].type].apply(null,e[l].matches),n[v]){for(r=++l;o>r;r++)if(i.relative[e[r].type])break;return bt(l>1&&vt(f),l>1&&mt(e.slice(0,l-1).concat({value:" "===e[l-2].type?"*":""})).replace(z,"$1"),n,r>l&&wt(e.slice(l,r)),o>r&&wt(e=e.slice(r)),o>r&&mt(e))}f.push(n)}return vt(f)}function Tt(e,t){var n=0,o=t.length>0,s=e.length>0,a=function(a,l,c,f,h){var d,g,m,y=[],v=0,x="0",b=a&&[],T=null!=h,C=u,k=a||s&&i.find.TAG("*",h&&l.parentNode||l),N=w+=null==C?1:Math.random()||.1;for(T&&(u=l!==p&&l,r=n);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,c)){f.push(d);break}T&&(w=N,r=++n)}o&&((d=!m&&d)&&v--,a&&b.push(d))}if(v+=x,o&&x!==v){g=0;while(m=t[g++])m(b,y,l,c);if(a){if(v>0)while(x--)b[x]||y[x]||(y[x]=q.call(f));y=xt(y)}O.apply(f,y),T&&!a&&y.length>0&&v+t.length>1&&ot.uniqueSort(f)}return T&&(w=N,u=C),b};return o?at(a):a}a=ot.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=gt(e)),n=t.length;while(n--)o=wt(t[n]),o[v]?r.push(o):i.push(o);o=N(e,Tt(i,r))}return o};function Ct(e,t,n){var r=0,i=t.length;for(;i>r;r++)ot(e,t[r],n);return n}function kt(e,t,r,o){var s,u,l,c,p,f=gt(e);if(!o&&1===f.length){if(u=f[0]=f[0].slice(0),u.length>2&&"ID"===(l=u[0]).type&&n.getById&&9===t.nodeType&&h&&i.relative[u[1].type]){if(t=(i.find.ID(l.matches[0].replace(nt,rt),t)||[])[0],!t)return r;e=e.slice(u.shift().value.length)}s=J.needsContext.test(e)?0:u.length;while(s--){if(l=u[s],i.relative[c=l.type])break;if((p=i.find[c])&&(o=p(l.matches[0].replace(nt,rt),U.test(u[0].type)&&t.parentNode||t))){if(u.splice(s,1),e=o.length&&mt(u),!e)return O.apply(r,o),r;break}}}return a(e,f)(o,t,!h,r,U.test(e)),r}n.sortStable=v.split("").sort(S).join("")===v,n.detectDuplicates=E,c(),n.sortDetached=ut(function(e){return 1&e.compareDocumentPosition(p.createElement("div"))}),ut(function(e){return e.innerHTML="<a href='#'></a>","#"===e.firstChild.getAttribute("href")})||lt("type|href|height|width",function(e,t,n){return n?undefined:e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ut(function(e){return e.innerHTML="<input/>",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||lt("value",function(e,t,n){return n||"input"!==e.nodeName.toLowerCase()?undefined:e.defaultValue}),ut(function(e){return null==e.getAttribute("disabled")})||lt(R,function(e,t,n){var r;return n?undefined:(r=e.getAttributeNode(t))&&r.specified?r.value:e[t]===!0?t.toLowerCase():null}),x.find=ot,x.expr=ot.selectors,x.expr[":"]=x.expr.pseudos,x.unique=ot.uniqueSort,x.text=ot.getText,x.isXMLDoc=ot.isXML,x.contains=ot.contains}(e);var D={};function A(e){var t=D[e]={};return x.each(e.match(w)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?D[e]||A(e):x.extend({},e);var t,n,r,i,o,s,a=[],u=!e.once&&[],l=function(p){for(t=e.memory&&p,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(p[0],p[1])===!1&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;(function s(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&c.has(n)||a.push(n):n&&n.length&&"string"!==r&&s(n)})})(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&x.each(arguments,function(e,t){var n;while((n=x.inArray(t,a,n))>-1)a.splice(n,1),r&&(o>=n&&o--,s>=n&&s--)}),this},has:function(e){return e?x.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=undefined,this},disabled:function(){return!a},lock:function(){return u=undefined,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return!a||n&&!u||(t=t||[],t=[e,t.slice?t.slice():t],r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var s=o[0],a=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=d.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),s=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?d.call(arguments):r,n===a?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},a,u,l;if(r>1)for(a=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(s(t,l,n)).fail(o.reject).progress(s(t,u,a)):--i;return i||o.resolveWith(l,n),o.promise()}}),x.support=function(t){var n=o.createElement("input"),r=o.createDocumentFragment(),i=o.createElement("div"),s=o.createElement("select"),a=s.appendChild(o.createElement("option"));return n.type?(n.type="checkbox",t.checkOn=""!==n.value,t.optSelected=a.selected,t.reliableMarginRight=!0,t.boxSizingReliable=!0,t.pixelPosition=!1,n.checked=!0,t.noCloneChecked=n.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!a.disabled,n=o.createElement("input"),n.value="t",n.type="radio",t.radioValue="t"===n.value,n.setAttribute("checked","t"),n.setAttribute("name","t"),r.appendChild(n),t.checkClone=r.cloneNode(!0).cloneNode(!0).lastChild.checked,t.focusinBubbles="onfocusin"in e,i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===i.style.backgroundClip,x(function(){var n,r,s="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",a=o.getElementsByTagName("body")[0];a&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",a.appendChild(n).appendChild(i),i.innerHTML="",i.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",x.swap(a,null!=a.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===i.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(i,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(i,null)||{width:"4px"}).width,r=i.appendChild(o.createElement("div")),r.style.cssText=i.style.cssText=s,r.style.marginRight=r.style.width="0",i.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),a.removeChild(n))}),t):t}({});var L,q,H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,O=/([A-Z])/g;function F(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=x.expando+Math.random()}F.uid=1,F.accepts=function(e){return e.nodeType?1===e.nodeType||9===e.nodeType:!0},F.prototype={key:function(e){if(!F.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=F.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,x.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(x.isEmptyObject(o))x.extend(this.cache[i],t);else for(r in t)o[r]=t[r];return o},get:function(e,t){var n=this.cache[this.key(e)];return t===undefined?n:n[t]},access:function(e,t,n){var r;return t===undefined||t&&"string"==typeof t&&n===undefined?(r=this.get(e,t),r!==undefined?r:this.get(e,x.camelCase(t))):(this.set(e,t,n),n!==undefined?n:t)},remove:function(e,t){var n,r,i,o=this.key(e),s=this.cache[o];if(t===undefined)this.cache[o]={};else{x.isArray(t)?r=t.concat(t.map(x.camelCase)):(i=x.camelCase(t),t in s?r=[t,i]:(r=i,r=r in s?[r]:r.match(w)||[])),n=r.length;while(n--)delete s[r[n]]}},hasData:function(e){return!x.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){e[this.expando]&&delete this.cache[e[this.expando]]}},L=new F,q=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||q.hasData(e)},data:function(e,t,n){return L.access(e,t,n)},removeData:function(e,t){L.remove(e,t)},_data:function(e,t,n){return q.access(e,t,n)},_removeData:function(e,t){q.remove(e,t)}}),x.fn.extend({data:function(e,t){var n,r,i=this[0],o=0,s=null;if(e===undefined){if(this.length&&(s=L.get(i),1===i.nodeType&&!q.get(i,"hasDataAttrs"))){for(n=i.attributes;n.length>o;o++)r=n[o].name,0===r.indexOf("data-")&&(r=x.camelCase(r.slice(5)),P(i,r,s[r]));q.set(i,"hasDataAttrs",!0)}return s}return"object"==typeof e?this.each(function(){L.set(this,e)}):x.access(this,function(t){var n,r=x.camelCase(e);if(i&&t===undefined){if(n=L.get(i,e),n!==undefined)return n;if(n=L.get(i,r),n!==undefined)return n;if(n=P(i,r,undefined),n!==undefined)return n}else this.each(function(){var n=L.get(this,r);L.set(this,r,t),-1!==e.indexOf("-")&&n!==undefined&&L.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){L.remove(this,e)})}});function P(e,t,n){var r;if(n===undefined&&1===e.nodeType)if(r="data-"+t.replace(O,"-$1").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:H.test(n)?JSON.parse(n):n}catch(i){}L.set(e,t,n)}else n=undefined;return n}x.extend({queue:function(e,t,n){var r;return e?(t=(t||"fx")+"queue",r=q.get(e,t),n&&(!r||x.isArray(n)?r=q.access(e,t,x.makeArray(n)):r.push(n)),r||[]):undefined},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),s=function(){x.dequeue(e,t)
+};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return q.get(e,n)||q.access(e,n,{empty:x.Callbacks("once memory").add(function(){q.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t);x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=q.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n\f]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var t,i=0,o=x(this),s=e.match(w)||[];while(t=s[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else(n===r||"boolean"===n)&&(this.className&&q.set(this,"__className__",this.className),this.className=this.className||e===!1?"":q.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,x(this).val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.bool.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.bool.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,t,n){var r,i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return o=1!==s||!x.isXMLDoc(e),o&&(t=x.propFix[t]||t,i=x.propHooks[t]),n!==undefined?i&&"set"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||B.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),M={set:function(e,t,n){return t===!1?x.removeAttr(e,n):e.setAttribute(n,n),n}},x.each(x.expr.match.bool.source.match(/\w+/g),function(e,t){var n=x.expr.attrHandle[t]||x.find.attr;x.expr.attrHandle[t]=function(e,t,r){var i=x.expr.attrHandle[t],o=r?undefined:(x.expr.attrHandle[t]=undefined)!=n(e,t,r)?t.toLowerCase():null;return x.expr.attrHandle[t]=i,o}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,t){return x.isArray(t)?e.checked=x.inArray(x(e).val(),t)>=0:undefined}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var I=/^key/,z=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,X=/^([^.]*)(?:\.(.+)|)$/;function U(){return!0}function Y(){return!1}function V(){try{return o.activeElement}catch(e){}}x.event={global:{},add:function(e,t,n,i,o){var s,a,u,l,c,p,f,h,d,g,m,y=q.get(e);if(y){n.handler&&(s=n,n=s.handler,o=s.selector),n.guid||(n.guid=x.guid++),(l=y.events)||(l=y.events={}),(a=y.handle)||(a=y.handle=function(e){return typeof x===r||e&&x.event.triggered===e.type?undefined:x.event.dispatch.apply(a.elem,arguments)},a.elem=e),t=(t||"").match(w)||[""],c=t.length;while(c--)u=X.exec(t[c])||[],d=m=u[1],g=(u[2]||"").split(".").sort(),d&&(f=x.event.special[d]||{},d=(o?f.delegateType:f.bindType)||d,f=x.event.special[d]||{},p=x.extend({type:d,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&x.expr.match.needsContext.test(o),namespace:g.join(".")},s),(h=l[d])||(h=l[d]=[],h.delegateCount=0,f.setup&&f.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),f.add&&(f.add.call(e,p),p.handler.guid||(p.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,p):h.push(p),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,p,f,h,d,g,m=q.hasData(e)&&q.get(e);if(m&&(u=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(a=X.exec(t[l])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){p=x.event.special[h]||{},h=(r?p.delegateType:p.bindType)||h,f=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=f.length;while(o--)c=f[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(f.splice(o,1),c.selector&&f.delegateCount--,p.remove&&p.remove.call(e,c));s&&!f.length&&(p.teardown&&p.teardown.call(e,d,m.handle)!==!1||x.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)x.event.remove(e,h+t[l],n,r,!0);x.isEmptyObject(u)&&(delete m.handle,q.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,p,f,h=[r||o],d=y.call(t,"type")?t.type:t,g=y.call(t,"namespace")?t.namespace.split("."):[];if(a=u=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!_.test(d+x.event.triggered)&&(d.indexOf(".")>=0&&(g=d.split("."),d=g.shift(),g.sort()),c=0>d.indexOf(":")&&"on"+d,t=t[x.expando]?t:new x.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=g.join("."),t.namespace_re=t.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=r),n=null==n?[t]:x.makeArray(n,[t]),f=x.event.special[d]||{},i||!f.trigger||f.trigger.apply(r,n)!==!1)){if(!i&&!f.noBubble&&!x.isWindow(r)){for(l=f.delegateType||d,_.test(l+d)||(a=a.parentNode);a;a=a.parentNode)h.push(a),u=a;u===(r.ownerDocument||o)&&h.push(u.defaultView||u.parentWindow||e)}s=0;while((a=h[s++])&&!t.isPropagationStopped())t.type=s>1?l:f.bindType||d,p=(q.get(a,"events")||{})[t.type]&&q.get(a,"handle"),p&&p.apply(a,n),p=c&&a[c],p&&x.acceptData(a)&&p.apply&&p.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||f._default&&f._default.apply(h.pop(),n)!==!1||!x.acceptData(r)||c&&x.isFunction(r[d])&&!x.isWindow(r)&&(u=r[c],u&&(r[c]=null),x.event.triggered=d,r[d](),x.event.triggered=undefined,u&&(r[c]=u)),t.result}},dispatch:function(e){e=x.event.fix(e);var t,n,r,i,o,s=[],a=d.call(arguments),u=(q.get(this,"events")||{})[e.type]||[],l=x.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),t=0;while((i=s[t++])&&!e.isPropagationStopped()){e.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(o.namespace))&&(e.handleObj=o,e.data=o.data,r=((x.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a),r!==undefined&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(u.disabled!==!0||"click"!==e.type){for(r=[],n=0;a>n;n++)o=t[n],i=o.selector+" ",r[i]===undefined&&(r[i]=o.needsContext?x(i,this).index(u)>=0:x.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return t.length>a&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,s=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||o,r=n.documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||s===undefined||(e.which=1&s?1:2&s?3:4&s?2:0),e}},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,s=e,a=this.fixHooks[i];a||(this.fixHooks[i]=a=z.test(i)?this.mouseHooks:I.test(i)?this.keyHooks:{}),r=a.props?this.props.concat(a.props):this.props,e=new x.Event(s),t=r.length;while(t--)n=r[t],e[n]=s[n];return e.target||(e.target=o),3===e.target.nodeType&&(e.target=e.target.parentNode),a.filter?a.filter(e,s):e},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==V()&&this.focus?(this.focus(),!1):undefined},delegateType:"focusin"},blur:{trigger:function(){return this===V()&&this.blur?(this.blur(),!1):undefined},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&x.nodeName(this,"input")?(this.click(),!1):undefined},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},x.Event=function(e,t){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.getPreventDefault&&e.getPreventDefault()?U:Y):this.type=e,t&&x.extend(this,t),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,undefined):new x.Event(e,t)},x.Event.prototype={isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=U,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=U,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=U,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=undefined);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=undefined):null==r&&("string"==typeof t?(r=n,n=undefined):(r=n,n=t,t=undefined)),r===!1)r=Y;else if(!r)return this;return 1===i&&(o=r,r=function(e){return x().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=x.guid++)),this.each(function(){x.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,x(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return(t===!1||"function"==typeof t)&&(n=t,t=undefined),n===!1&&(n=Y),this.each(function(){x.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];return n?x.event.trigger(e,t,n,!0):undefined}});var G=/^.[^:#\[\.,]*$/,J=/^(?:parents|prev(?:Until|All))/,Q=x.expr.match.needsContext,K={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(x(e).filter(function(){for(t=0;i>t;t++)if(x.contains(r[t],this))return!0}));for(t=0;i>t;t++)x.find(e,r[t],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},has:function(e){var t=x(e,this),n=t.length;return this.filter(function(){var e=0;for(;n>e;e++)if(x.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(et(this,e||[],!0))},filter:function(e){return this.pushStack(et(this,e||[],!1))},is:function(e){return!!et(this,"string"==typeof e&&Q.test(e)?x(e):e||[],!1).length},closest:function(e,t){var n,r=0,i=this.length,o=[],s=Q.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(s?s.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?g.call(x(e),this[0]):g.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function Z(e,t){while((e=e[t])&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return Z(e,"nextSibling")},prev:function(e){return Z(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return e.contentDocument||x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(K[e]||x.unique(i),J.test(e)&&i.reverse()),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,t,n){var r=[],i=n!==undefined;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&x(e).is(n))break;r.push(e)}return r},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function et(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(G.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return g.call(t,e)>=0!==n})}var tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,nt=/<([\w:]+)/,rt=/<|&#?\w+;/,it=/<(?:script|style|link)/i,ot=/^(?:checkbox|radio)$/i,st=/checked\s*(?:[^=]|=\s*.checked.)/i,at=/^$|\/(?:java|ecma)script/i,ut=/^true\/(.*)/,lt=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ct={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ct.optgroup=ct.option,ct.tbody=ct.tfoot=ct.colgroup=ct.caption=ct.thead,ct.th=ct.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===undefined?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=pt(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(mt(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&dt(mt(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++)1===e.nodeType&&(x.cleanData(mt(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!it.test(e)&&!ct[(nt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(tt,"<$1></$2>");try{for(;r>n;n++)t=this[n]||{},1===t.nodeType&&(x.cleanData(mt(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(r&&r.parentNode!==i&&(r=this.nextSibling),x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=f.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,p=this,h=c-1,d=e[0],g=x.isFunction(d);if(g||!(1>=c||"string"!=typeof d||x.support.checkClone)&&st.test(d))return this.each(function(r){var i=p.eq(r);g&&(e[0]=d.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(r=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),i=r.firstChild,1===r.childNodes.length&&(r=i),i)){for(o=x.map(mt(r,"script"),ft),s=o.length;c>l;l++)a=r,l!==h&&(a=x.clone(a,!0,!0),s&&x.merge(o,mt(a,"script"))),t.call(this[l],a,l);if(s)for(u=o[o.length-1].ownerDocument,x.map(o,ht),l=0;s>l;l++)a=o[l],at.test(a.type||"")&&!q.access(a,"globalEval")&&x.contains(u,a)&&(a.src?x._evalUrl(a.src):x.globalEval(a.textContent.replace(lt,"")))}return this}}),x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=[],i=x(e),o=i.length-1,s=0;for(;o>=s;s++)n=s===o?this:this.clone(!0),x(i[s])[t](n),h.apply(r,n.get());return this.pushStack(r)}}),x.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=x.contains(e.ownerDocument,e);if(!(x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(s=mt(a),o=mt(e),r=0,i=o.length;i>r;r++)yt(o[r],s[r]);if(t)if(n)for(o=o||mt(e),s=s||mt(a),r=0,i=o.length;i>r;r++)gt(o[r],s[r]);else gt(e,a);return s=mt(a,"script"),s.length>0&&dt(s,!u&&mt(e,"script")),a},buildFragment:function(e,t,n,r){var i,o,s,a,u,l,c=0,p=e.length,f=t.createDocumentFragment(),h=[];for(;p>c;c++)if(i=e[c],i||0===i)if("object"===x.type(i))x.merge(h,i.nodeType?[i]:i);else if(rt.test(i)){o=o||f.appendChild(t.createElement("div")),s=(nt.exec(i)||["",""])[1].toLowerCase(),a=ct[s]||ct._default,o.innerHTML=a[1]+i.replace(tt,"<$1></$2>")+a[2],l=a[0];while(l--)o=o.lastChild;x.merge(h,o.childNodes),o=f.firstChild,o.textContent=""}else h.push(t.createTextNode(i));f.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=mt(f.appendChild(i),"script"),u&&dt(o),n)){l=0;while(i=o[l++])at.test(i.type||"")&&n.push(i)}return f},cleanData:function(e){var t,n,r,i,o,s,a=x.event.special,u=0;for(;(n=e[u])!==undefined;u++){if(F.accepts(n)&&(o=n[q.expando],o&&(t=q.cache[o]))){if(r=Object.keys(t.events||{}),r.length)for(s=0;(i=r[s])!==undefined;s++)a[i]?x.event.remove(n,i):x.removeEvent(n,i,t.handle);q.cache[o]&&delete q.cache[o]}delete L.cache[n[L.expando]]}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})}});function pt(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function ft(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function ht(e){var t=ut.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function dt(e,t){var n=e.length,r=0;for(;n>r;r++)q.set(e[r],"globalEval",!t||q.get(t[r],"globalEval"))}function gt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(q.hasData(e)&&(o=q.access(e),s=q.set(t,o),l=o.events)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;r>n;n++)x.event.add(t,i,l[i][n])}L.hasData(e)&&(a=L.access(e),u=x.extend({},a),L.set(t,u))}}function mt(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return t===undefined||t&&x.nodeName(e,t)?x.merge([e],n):n}function yt(e,t){var n=t.nodeName.toLowerCase();"input"===n&&ot.test(e.type)?t.checked=e.checked:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}x.fn.extend({wrapAll:function(e){var t;return x.isFunction(e)?this.each(function(t){x(this).wrapAll(e.call(this,t))}):(this[0]&&(t=x(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var vt,xt,bt=/^(none|table(?!-c[ea]).+)/,wt=/^margin/,Tt=RegExp("^("+b+")(.*)$","i"),Ct=RegExp("^("+b+")(?!px)[a-z%]+$","i"),kt=RegExp("^([+-])=("+b+")","i"),Nt={BODY:"block"},Et={position:"absolute",visibility:"hidden",display:"block"},St={letterSpacing:0,fontWeight:400},jt=["Top","Right","Bottom","Left"],Dt=["Webkit","O","Moz","ms"];function At(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=Dt.length;while(i--)if(t=Dt[i]+n,t in e)return t;return r}function Lt(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function qt(t){return e.getComputedStyle(t,null)}function Ht(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=q.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&Lt(r)&&(o[s]=q.access(r,"olddisplay",Rt(r.nodeName)))):o[s]||(i=Lt(r),(n&&"none"!==n||!i)&&q.set(r,"olddisplay",i?n:x.css(r,"display"))));for(s=0;a>s;s++)r=e[s],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}x.fn.extend({css:function(e,t){return x.access(this,function(e,t,n){var r,i,o={},s=0;if(x.isArray(t)){for(r=qt(e),i=t.length;i>s;s++)o[t[s]]=x.css(e,t[s],!1,r);return o}return n!==undefined?x.style(e,t,n):x.css(e,t)},e,t,arguments.length>1)},show:function(){return Ht(this,!0)},hide:function(){return Ht(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){Lt(this)?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=vt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=x.camelCase(t),u=e.style;return t=x.cssProps[a]||(x.cssProps[a]=At(u,a)),s=x.cssHooks[t]||x.cssHooks[a],n===undefined?s&&"get"in s&&(i=s.get(e,!1,r))!==undefined?i:u[t]:(o=typeof n,"string"===o&&(i=kt.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(x.css(e,t)),o="number"),null==n||"number"===o&&isNaN(n)||("number"!==o||x.cssNumber[a]||(n+="px"),x.support.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&(n=s.set(e,n,r))===undefined||(u[t]=n)),undefined)}},css:function(e,t,n,r){var i,o,s,a=x.camelCase(t);return t=x.cssProps[a]||(x.cssProps[a]=At(e.style,a)),s=x.cssHooks[t]||x.cssHooks[a],s&&"get"in s&&(i=s.get(e,!0,n)),i===undefined&&(i=vt(e,t,r)),"normal"===i&&t in St&&(i=St[t]),""===n||n?(o=parseFloat(i),n===!0||x.isNumeric(o)?o||0:i):i}}),vt=function(e,t,n){var r,i,o,s=n||qt(e),a=s?s.getPropertyValue(t)||s[t]:undefined,u=e.style;return s&&(""!==a||x.contains(e.ownerDocument,e)||(a=x.style(e,t)),Ct.test(a)&&wt.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=s.width,u.width=r,u.minWidth=i,u.maxWidth=o)),a};function Ot(e,t,n){var r=Tt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function Ft(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;for(;4>o;o+=2)"margin"===n&&(s+=x.css(e,n+jt[o],!0,i)),r?("content"===n&&(s-=x.css(e,"padding"+jt[o],!0,i)),"margin"!==n&&(s-=x.css(e,"border"+jt[o]+"Width",!0,i))):(s+=x.css(e,"padding"+jt[o],!0,i),"padding"!==n&&(s+=x.css(e,"border"+jt[o]+"Width",!0,i)));return s}function Pt(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=qt(e),s=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=vt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Ct.test(i))return i;r=s&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+Ft(e,t,n||(s?"border":"content"),r,o)+"px"}function Rt(e){var t=o,n=Nt[e];return n||(n=Mt(e,t),"none"!==n&&n||(xt=(xt||x("<iframe frameborder='0' width='0' height='0'/>").css("cssText","display:block !important")).appendTo(t.documentElement),t=(xt[0].contentWindow||xt[0].contentDocument).document,t.write("<!doctype html><html><body>"),t.close(),n=Mt(e,t),xt.detach()),Nt[e]=n),n}function Mt(e,t){var n=x(t.createElement(e)).appendTo(t.body),r=x.css(n[0],"display");return n.remove(),r}x.each(["height","width"],function(e,t){x.cssHooks[t]={get:function(e,n,r){return n?0===e.offsetWidth&&bt.test(x.css(e,"display"))?x.swap(e,Et,function(){return Pt(e,t,r)}):Pt(e,t,r):undefined},set:function(e,n,r){var i=r&&qt(e);return Ot(e,n,r?Ft(e,t,r,x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,i),i):0)}}}),x(function(){x.support.reliableMarginRight||(x.cssHooks.marginRight={get:function(e,t){return t?x.swap(e,{display:"inline-block"},vt,[e,"marginRight"]):undefined}}),!x.support.pixelPosition&&x.fn.position&&x.each(["top","left"],function(e,t){x.cssHooks[t]={get:function(e,n){return n?(n=vt(e,t),Ct.test(n)?x(e).position()[t]+"px":n):undefined}}})}),x.expr&&x.expr.filters&&(x.expr.filters.hidden=function(e){return 0>=e.offsetWidth&&0>=e.offsetHeight},x.expr.filters.visible=function(e){return!x.expr.filters.hidden(e)}),x.each({margin:"",padding:"",border:"Width"},function(e,t){x.cssHooks[e+t]={expand:function(n){var r=0,i={},o="string"==typeof n?n.split(" "):[n];for(;4>r;r++)i[e+jt[r]+t]=o[r]||o[r-2]||o[0];return i}},wt.test(e)||(x.cssHooks[e+t].set=Ot)});var Wt=/%20/g,$t=/\[\]$/,Bt=/\r?\n/g,It=/^(?:submit|button|image|reset|file)$/i,zt=/^(?:input|select|textarea|keygen)/i;x.fn.extend({serialize:function(){return x.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=x.prop(this,"elements");return e?x.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!x(this).is(":disabled")&&zt.test(this.nodeName)&&!It.test(e)&&(this.checked||!ot.test(e))}).map(function(e,t){var n=x(this).val();return null==n?null:x.isArray(n)?x.map(n,function(e){return{name:t.name,value:e.replace(Bt,"\r\n")}}):{name:t.name,value:n.replace(Bt,"\r\n")}}).get()}}),x.param=function(e,t){var n,r=[],i=function(e,t){t=x.isFunction(t)?t():null==t?"":t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(t===undefined&&(t=x.ajaxSettings&&x.ajaxSettings.traditional),x.isArray(e)||e.jquery&&!x.isPlainObject(e))x.each(e,function(){i(this.name,this.value)});else for(n in e)_t(n,e[n],t,i);return r.join("&").replace(Wt,"+")};function _t(e,t,n,r){var i;if(x.isArray(t))x.each(t,function(t,i){n||$t.test(e)?r(e,i):_t(e+"["+("object"==typeof i?t:"")+"]",i,n,r)});else if(n||"object"!==x.type(t))r(e,t);else for(i in t)_t(e+"["+i+"]",t[i],n,r)}x.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){x.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),x.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)
+},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}});var Xt,Ut,Yt=x.now(),Vt=/\?/,Gt=/#.*$/,Jt=/([?&])_=[^&]*/,Qt=/^(.*?):[ \t]*([^\r\n]*)$/gm,Kt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Zt=/^(?:GET|HEAD)$/,en=/^\/\//,tn=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/,nn=x.fn.load,rn={},on={},sn="*/".concat("*");try{Ut=i.href}catch(an){Ut=o.createElement("a"),Ut.href="",Ut=Ut.href}Xt=tn.exec(Ut.toLowerCase())||[];function un(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(w)||[];if(x.isFunction(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function ln(e,t,n,r){var i={},o=e===on;function s(a){var u;return i[a]=!0,x.each(e[a]||[],function(e,a){var l=a(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):undefined:(t.dataTypes.unshift(l),s(l),!1)}),u}return s(t.dataTypes[0])||!i["*"]&&s("*")}function cn(e,t){var n,r,i=x.ajaxSettings.flatOptions||{};for(n in t)t[n]!==undefined&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&x.extend(!0,e,r),e}x.fn.load=function(e,t,n){if("string"!=typeof e&&nn)return nn.apply(this,arguments);var r,i,o,s=this,a=e.indexOf(" ");return a>=0&&(r=e.slice(a),e=e.slice(0,a)),x.isFunction(t)?(n=t,t=undefined):t&&"object"==typeof t&&(i="POST"),s.length>0&&x.ajax({url:e,type:i,dataType:"html",data:t}).done(function(e){o=arguments,s.html(r?x("<div>").append(x.parseHTML(e)).find(r):e)}).complete(n&&function(e,t){s.each(n,o||[e.responseText,t,e])}),this},x.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){x.fn[t]=function(e){return this.on(t,e)}}),x.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ut,type:"GET",isLocal:Kt.test(Xt[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":sn,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":x.parseJSON,"text xml":x.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?cn(cn(e,x.ajaxSettings),t):cn(x.ajaxSettings,e)},ajaxPrefilter:un(rn),ajaxTransport:un(on),ajax:function(e,t){"object"==typeof e&&(t=e,e=undefined),t=t||{};var n,r,i,o,s,a,u,l,c=x.ajaxSetup({},t),p=c.context||c,f=c.context&&(p.nodeType||p.jquery)?x(p):x.event,h=x.Deferred(),d=x.Callbacks("once memory"),g=c.statusCode||{},m={},y={},v=0,b="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(2===v){if(!o){o={};while(t=Qt.exec(i))o[t[1].toLowerCase()]=t[2]}t=o[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===v?i:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return v||(e=y[n]=y[n]||e,m[e]=t),this},overrideMimeType:function(e){return v||(c.mimeType=e),this},statusCode:function(e){var t;if(e)if(2>v)for(t in e)g[t]=[g[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||b;return n&&n.abort(t),k(0,t),this}};if(h.promise(T).complete=d.add,T.success=T.done,T.error=T.fail,c.url=((e||c.url||Ut)+"").replace(Gt,"").replace(en,Xt[1]+"//"),c.type=t.method||t.type||c.method||c.type,c.dataTypes=x.trim(c.dataType||"*").toLowerCase().match(w)||[""],null==c.crossDomain&&(a=tn.exec(c.url.toLowerCase()),c.crossDomain=!(!a||a[1]===Xt[1]&&a[2]===Xt[2]&&(a[3]||("http:"===a[1]?"80":"443"))===(Xt[3]||("http:"===Xt[1]?"80":"443")))),c.data&&c.processData&&"string"!=typeof c.data&&(c.data=x.param(c.data,c.traditional)),ln(rn,c,t,T),2===v)return T;u=c.global,u&&0===x.active++&&x.event.trigger("ajaxStart"),c.type=c.type.toUpperCase(),c.hasContent=!Zt.test(c.type),r=c.url,c.hasContent||(c.data&&(r=c.url+=(Vt.test(r)?"&":"?")+c.data,delete c.data),c.cache===!1&&(c.url=Jt.test(r)?r.replace(Jt,"$1_="+Yt++):r+(Vt.test(r)?"&":"?")+"_="+Yt++)),c.ifModified&&(x.lastModified[r]&&T.setRequestHeader("If-Modified-Since",x.lastModified[r]),x.etag[r]&&T.setRequestHeader("If-None-Match",x.etag[r])),(c.data&&c.hasContent&&c.contentType!==!1||t.contentType)&&T.setRequestHeader("Content-Type",c.contentType),T.setRequestHeader("Accept",c.dataTypes[0]&&c.accepts[c.dataTypes[0]]?c.accepts[c.dataTypes[0]]+("*"!==c.dataTypes[0]?", "+sn+"; q=0.01":""):c.accepts["*"]);for(l in c.headers)T.setRequestHeader(l,c.headers[l]);if(c.beforeSend&&(c.beforeSend.call(p,T,c)===!1||2===v))return T.abort();b="abort";for(l in{success:1,error:1,complete:1})T[l](c[l]);if(n=ln(on,c,t,T)){T.readyState=1,u&&f.trigger("ajaxSend",[T,c]),c.async&&c.timeout>0&&(s=setTimeout(function(){T.abort("timeout")},c.timeout));try{v=1,n.send(m,k)}catch(C){if(!(2>v))throw C;k(-1,C)}}else k(-1,"No Transport");function k(e,t,o,a){var l,m,y,b,w,C=t;2!==v&&(v=2,s&&clearTimeout(s),n=undefined,i=a||"",T.readyState=e>0?4:0,l=e>=200&&300>e||304===e,o&&(b=pn(c,T,o)),b=fn(c,b,T,l),l?(c.ifModified&&(w=T.getResponseHeader("Last-Modified"),w&&(x.lastModified[r]=w),w=T.getResponseHeader("etag"),w&&(x.etag[r]=w)),204===e||"HEAD"===c.type?C="nocontent":304===e?C="notmodified":(C=b.state,m=b.data,y=b.error,l=!y)):(y=C,(e||!C)&&(C="error",0>e&&(e=0))),T.status=e,T.statusText=(t||C)+"",l?h.resolveWith(p,[m,C,T]):h.rejectWith(p,[T,C,y]),T.statusCode(g),g=undefined,u&&f.trigger(l?"ajaxSuccess":"ajaxError",[T,c,l?m:y]),d.fireWith(p,[T,C]),u&&(f.trigger("ajaxComplete",[T,c]),--x.active||x.event.trigger("ajaxStop")))}return T},getJSON:function(e,t,n){return x.get(e,t,n,"json")},getScript:function(e,t){return x.get(e,undefined,t,"script")}}),x.each(["get","post"],function(e,t){x[t]=function(e,n,r,i){return x.isFunction(n)&&(i=i||r,r=n,n=undefined),x.ajax({url:e,type:t,dataType:i,data:n,success:r})}});function pn(e,t,n){var r,i,o,s,a=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),r===undefined&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in a)if(a[i]&&a[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}s||(s=i)}o=o||s}return o?(o!==u[0]&&u.unshift(o),n[o]):undefined}function fn(e,t,n,r){var i,o,s,a,u,l={},c=e.dataTypes.slice();if(c[1])for(s in e.converters)l[s.toLowerCase()]=e.converters[s];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(s=l[u+" "+o]||l["* "+o],!s)for(i in l)if(a=i.split(" "),a[1]===o&&(s=l[u+" "+a[0]]||l["* "+a[0]])){s===!0?s=l[i]:l[i]!==!0&&(o=a[0],c.unshift(a[1]));break}if(s!==!0)if(s&&e["throws"])t=s(t);else try{t=s(t)}catch(p){return{state:"parsererror",error:s?p:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}x.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(e){return x.globalEval(e),e}}}),x.ajaxPrefilter("script",function(e){e.cache===undefined&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),x.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(r,i){t=x("<script>").prop({async:!0,charset:e.scriptCharset,src:e.url}).on("load error",n=function(e){t.remove(),n=null,e&&i("error"===e.type?404:200,e.type)}),o.head.appendChild(t[0])},abort:function(){n&&n()}}}});var hn=[],dn=/(=)\?(?=&|$)|\?\?/;x.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=hn.pop()||x.expando+"_"+Yt++;return this[e]=!0,e}}),x.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,s,a=t.jsonp!==!1&&(dn.test(t.url)?"url":"string"==typeof t.data&&!(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&dn.test(t.data)&&"data");return a||"jsonp"===t.dataTypes[0]?(i=t.jsonpCallback=x.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,a?t[a]=t[a].replace(dn,"$1"+i):t.jsonp!==!1&&(t.url+=(Vt.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return s||x.error(i+" was not called"),s[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){s=arguments},r.always(function(){e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,hn.push(i)),s&&x.isFunction(o)&&o(s[0]),s=o=undefined}),"script"):undefined}),x.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(e){}};var gn=x.ajaxSettings.xhr(),mn={0:200,1223:204},yn=0,vn={};e.ActiveXObject&&x(e).on("unload",function(){for(var e in vn)vn[e]();vn=undefined}),x.support.cors=!!gn&&"withCredentials"in gn,x.support.ajax=gn=!!gn,x.ajaxTransport(function(e){var t;return x.support.cors||gn&&!e.crossDomain?{send:function(n,r){var i,o,s=e.xhr();if(s.open(e.type,e.url,e.async,e.username,e.password),e.xhrFields)for(i in e.xhrFields)s[i]=e.xhrFields[i];e.mimeType&&s.overrideMimeType&&s.overrideMimeType(e.mimeType),e.crossDomain||n["X-Requested-With"]||(n["X-Requested-With"]="XMLHttpRequest");for(i in n)s.setRequestHeader(i,n[i]);t=function(e){return function(){t&&(delete vn[o],t=s.onload=s.onerror=null,"abort"===e?s.abort():"error"===e?r(s.status||404,s.statusText):r(mn[s.status]||s.status,s.statusText,"string"==typeof s.responseText?{text:s.responseText}:undefined,s.getAllResponseHeaders()))}},s.onload=t(),s.onerror=t("error"),t=vn[o=yn++]=t("abort"),s.send(e.hasContent&&e.data||null)},abort:function(){t&&t()}}:undefined});var xn,bn,wn=/^(?:toggle|show|hide)$/,Tn=RegExp("^(?:([+-])=|)("+b+")([a-z%]*)$","i"),Cn=/queueHooks$/,kn=[An],Nn={"*":[function(e,t){var n=this.createTween(e,t),r=n.cur(),i=Tn.exec(t),o=i&&i[3]||(x.cssNumber[e]?"":"px"),s=(x.cssNumber[e]||"px"!==o&&+r)&&Tn.exec(x.css(n.elem,e)),a=1,u=20;if(s&&s[3]!==o){o=o||s[3],i=i||[],s=+r||1;do a=a||".5",s/=a,x.style(n.elem,e,s+o);while(a!==(a=n.cur()/r)&&1!==a&&--u)}return i&&(s=n.start=+s||+r||0,n.unit=o,n.end=i[1]?s+(i[1]+1)*i[2]:+i[2]),n}]};function En(){return setTimeout(function(){xn=undefined}),xn=x.now()}function Sn(e,t,n){var r,i=(Nn[t]||[]).concat(Nn["*"]),o=0,s=i.length;for(;s>o;o++)if(r=i[o].call(n,t,e))return r}function jn(e,t,n){var r,i,o=0,s=kn.length,a=x.Deferred().always(function(){delete u.elem}),u=function(){if(i)return!1;var t=xn||En(),n=Math.max(0,l.startTime+l.duration-t),r=n/l.duration||0,o=1-r,s=0,u=l.tweens.length;for(;u>s;s++)l.tweens[s].run(o);return a.notifyWith(e,[l,o,n]),1>o&&u?n:(a.resolveWith(e,[l]),!1)},l=a.promise({elem:e,props:x.extend({},t),opts:x.extend(!0,{specialEasing:{}},n),originalProperties:t,originalOptions:n,startTime:xn||En(),duration:n.duration,tweens:[],createTween:function(t,n){var r=x.Tween(e,l.opts,t,n,l.opts.specialEasing[t]||l.opts.easing);return l.tweens.push(r),r},stop:function(t){var n=0,r=t?l.tweens.length:0;if(i)return this;for(i=!0;r>n;n++)l.tweens[n].run(1);return t?a.resolveWith(e,[l,t]):a.rejectWith(e,[l,t]),this}}),c=l.props;for(Dn(c,l.opts.specialEasing);s>o;o++)if(r=kn[o].call(l,e,c,l.opts))return r;return x.map(c,Sn,l),x.isFunction(l.opts.start)&&l.opts.start.call(e,l),x.fx.timer(x.extend(u,{elem:e,anim:l,queue:l.opts.queue})),l.progress(l.opts.progress).done(l.opts.done,l.opts.complete).fail(l.opts.fail).always(l.opts.always)}function Dn(e,t){var n,r,i,o,s;for(n in e)if(r=x.camelCase(n),i=t[r],o=e[n],x.isArray(o)&&(i=o[1],o=e[n]=o[0]),n!==r&&(e[r]=o,delete e[n]),s=x.cssHooks[r],s&&"expand"in s){o=s.expand(o),delete e[r];for(n in o)n in e||(e[n]=o[n],t[n]=i)}else t[r]=i}x.Animation=x.extend(jn,{tweener:function(e,t){x.isFunction(e)?(t=e,e=["*"]):e=e.split(" ");var n,r=0,i=e.length;for(;i>r;r++)n=e[r],Nn[n]=Nn[n]||[],Nn[n].unshift(t)},prefilter:function(e,t){t?kn.unshift(e):kn.push(e)}});function An(e,t,n){var r,i,o,s,a,u,l=this,c={},p=e.style,f=e.nodeType&&Lt(e),h=q.get(e,"fxshow");n.queue||(a=x._queueHooks(e,"fx"),null==a.unqueued&&(a.unqueued=0,u=a.empty.fire,a.empty.fire=function(){a.unqueued||u()}),a.unqueued++,l.always(function(){l.always(function(){a.unqueued--,x.queue(e,"fx").length||a.empty.fire()})})),1===e.nodeType&&("height"in t||"width"in t)&&(n.overflow=[p.overflow,p.overflowX,p.overflowY],"inline"===x.css(e,"display")&&"none"===x.css(e,"float")&&(p.display="inline-block")),n.overflow&&(p.overflow="hidden",l.always(function(){p.overflow=n.overflow[0],p.overflowX=n.overflow[1],p.overflowY=n.overflow[2]}));for(r in t)if(i=t[r],wn.exec(i)){if(delete t[r],o=o||"toggle"===i,i===(f?"hide":"show")){if("show"!==i||!h||h[r]===undefined)continue;f=!0}c[r]=h&&h[r]||x.style(e,r)}if(!x.isEmptyObject(c)){h?"hidden"in h&&(f=h.hidden):h=q.access(e,"fxshow",{}),o&&(h.hidden=!f),f?x(e).show():l.done(function(){x(e).hide()}),l.done(function(){var t;q.remove(e,"fxshow");for(t in c)x.style(e,t,c[t])});for(r in c)s=Sn(f?h[r]:0,r,l),r in h||(h[r]=s.start,f&&(s.end=s.start,s.start="width"===r||"height"===r?1:0))}}function Ln(e,t,n,r,i){return new Ln.prototype.init(e,t,n,r,i)}x.Tween=Ln,Ln.prototype={constructor:Ln,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||"swing",this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(x.cssNumber[n]?"":"px")},cur:function(){var e=Ln.propHooks[this.prop];return e&&e.get?e.get(this):Ln.propHooks._default.get(this)},run:function(e){var t,n=Ln.propHooks[this.prop];return this.pos=t=this.options.duration?x.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):Ln.propHooks._default.set(this),this}},Ln.prototype.init.prototype=Ln.prototype,Ln.propHooks={_default:{get:function(e){var t;return null==e.elem[e.prop]||e.elem.style&&null!=e.elem.style[e.prop]?(t=x.css(e.elem,e.prop,""),t&&"auto"!==t?t:0):e.elem[e.prop]},set:function(e){x.fx.step[e.prop]?x.fx.step[e.prop](e):e.elem.style&&(null!=e.elem.style[x.cssProps[e.prop]]||x.cssHooks[e.prop])?x.style(e.elem,e.prop,e.now+e.unit):e.elem[e.prop]=e.now}}},Ln.propHooks.scrollTop=Ln.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},x.each(["toggle","show","hide"],function(e,t){var n=x.fn[t];x.fn[t]=function(e,r,i){return null==e||"boolean"==typeof e?n.apply(this,arguments):this.animate(qn(t,!0),e,r,i)}}),x.fn.extend({fadeTo:function(e,t,n,r){return this.filter(Lt).css("opacity",0).show().end().animate({opacity:t},e,n,r)},animate:function(e,t,n,r){var i=x.isEmptyObject(e),o=x.speed(t,n,r),s=function(){var t=jn(this,x.extend({},e),o);(i||q.get(this,"finish"))&&t.stop(!0)};return s.finish=s,i||o.queue===!1?this.each(s):this.queue(o.queue,s)},stop:function(e,t,n){var r=function(e){var t=e.stop;delete e.stop,t(n)};return"string"!=typeof e&&(n=t,t=e,e=undefined),t&&e!==!1&&this.queue(e||"fx",[]),this.each(function(){var t=!0,i=null!=e&&e+"queueHooks",o=x.timers,s=q.get(this);if(i)s[i]&&s[i].stop&&r(s[i]);else for(i in s)s[i]&&s[i].stop&&Cn.test(i)&&r(s[i]);for(i=o.length;i--;)o[i].elem!==this||null!=e&&o[i].queue!==e||(o[i].anim.stop(n),t=!1,o.splice(i,1));(t||!n)&&x.dequeue(this,e)})},finish:function(e){return e!==!1&&(e=e||"fx"),this.each(function(){var t,n=q.get(this),r=n[e+"queue"],i=n[e+"queueHooks"],o=x.timers,s=r?r.length:0;for(n.finish=!0,x.queue(this,e,[]),i&&i.stop&&i.stop.call(this,!0),t=o.length;t--;)o[t].elem===this&&o[t].queue===e&&(o[t].anim.stop(!0),o.splice(t,1));for(t=0;s>t;t++)r[t]&&r[t].finish&&r[t].finish.call(this);delete n.finish})}});function qn(e,t){var n,r={height:e},i=0;for(t=t?1:0;4>i;i+=2-t)n=jt[i],r["margin"+n]=r["padding"+n]=e;return t&&(r.opacity=r.width=e),r}x.each({slideDown:qn("show"),slideUp:qn("hide"),slideToggle:qn("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(e,t){x.fn[e]=function(e,n,r){return this.animate(t,e,n,r)}}),x.speed=function(e,t,n){var r=e&&"object"==typeof e?x.extend({},e):{complete:n||!n&&t||x.isFunction(e)&&e,duration:e,easing:n&&t||t&&!x.isFunction(t)&&t};return r.duration=x.fx.off?0:"number"==typeof r.duration?r.duration:r.duration in x.fx.speeds?x.fx.speeds[r.duration]:x.fx.speeds._default,(null==r.queue||r.queue===!0)&&(r.queue="fx"),r.old=r.complete,r.complete=function(){x.isFunction(r.old)&&r.old.call(this),r.queue&&x.dequeue(this,r.queue)},r},x.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2}},x.timers=[],x.fx=Ln.prototype.init,x.fx.tick=function(){var e,t=x.timers,n=0;for(xn=x.now();t.length>n;n++)e=t[n],e()||t[n]!==e||t.splice(n--,1);t.length||x.fx.stop(),xn=undefined},x.fx.timer=function(e){e()&&x.timers.push(e)&&x.fx.start()},x.fx.interval=13,x.fx.start=function(){bn||(bn=setInterval(x.fx.tick,x.fx.interval))},x.fx.stop=function(){clearInterval(bn),bn=null},x.fx.speeds={slow:600,fast:200,_default:400},x.fx.step={},x.expr&&x.expr.filters&&(x.expr.filters.animated=function(e){return x.grep(x.timers,function(t){return e===t.elem}).length}),x.fn.offset=function(e){if(arguments.length)return e===undefined?this:this.each(function(t){x.offset.setOffset(this,e,t)});var t,n,i=this[0],o={top:0,left:0},s=i&&i.ownerDocument;if(s)return t=s.documentElement,x.contains(t,i)?(typeof i.getBoundingClientRect!==r&&(o=i.getBoundingClientRect()),n=Hn(s),{top:o.top+n.pageYOffset-t.clientTop,left:o.left+n.pageXOffset-t.clientLeft}):o},x.offset={setOffset:function(e,t,n){var r,i,o,s,a,u,l,c=x.css(e,"position"),p=x(e),f={};"static"===c&&(e.style.position="relative"),a=p.offset(),o=x.css(e,"top"),u=x.css(e,"left"),l=("absolute"===c||"fixed"===c)&&(o+u).indexOf("auto")>-1,l?(r=p.position(),s=r.top,i=r.left):(s=parseFloat(o)||0,i=parseFloat(u)||0),x.isFunction(t)&&(t=t.call(e,n,a)),null!=t.top&&(f.top=t.top-a.top+s),null!=t.left&&(f.left=t.left-a.left+i),"using"in t?t.using.call(e,f):p.css(f)}},x.fn.extend({position:function(){if(this[0]){var e,t,n=this[0],r={top:0,left:0};return"fixed"===x.css(n,"position")?t=n.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),x.nodeName(e[0],"html")||(r=e.offset()),r.top+=x.css(e[0],"borderTopWidth",!0),r.left+=x.css(e[0],"borderLeftWidth",!0)),{top:t.top-r.top-x.css(n,"marginTop",!0),left:t.left-r.left-x.css(n,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent||s;while(e&&!x.nodeName(e,"html")&&"static"===x.css(e,"position"))e=e.offsetParent;return e||s})}}),x.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,n){var r="pageYOffset"===n;x.fn[t]=function(i){return x.access(this,function(t,i,o){var s=Hn(t);return o===undefined?s?s[n]:t[i]:(s?s.scrollTo(r?e.pageXOffset:o,r?o:e.pageYOffset):t[i]=o,undefined)},t,i,arguments.length,null)}});function Hn(e){return x.isWindow(e)?e:9===e.nodeType&&e.defaultView}x.each({Height:"height",Width:"width"},function(e,t){x.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){x.fn[r]=function(r,i){var o=arguments.length&&(n||"boolean"!=typeof r),s=n||(r===!0||i===!0?"margin":"border");return x.access(this,function(t,n,r){var i;return x.isWindow(t)?t.document.documentElement["client"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body["scroll"+e],i["scroll"+e],t.body["offset"+e],i["offset"+e],i["client"+e])):r===undefined?x.css(t,n,s):x.style(t,n,r,s)},t,o?r:undefined,o,null)}})}),x.fn.size=function(){return this.length},x.fn.andSelf=x.fn.addBack,"object"==typeof module&&module&&"object"==typeof module.exports?module.exports=x:"function"==typeof define&&define.amd&&define("jquery",[],function(){return x}),"object"==typeof e&&"object"==typeof e.document&&(e.jQuery=e.$=x)})(window);
diff --git a/lib/erl_docgen/priv/xsl/db_html.xsl b/lib/erl_docgen/priv/xsl/db_html.xsl
index ab5f24c406..f8218659a4 100644
--- a/lib/erl_docgen/priv/xsl/db_html.xsl
+++ b/lib/erl_docgen/priv/xsl/db_html.xsl
@@ -309,10 +309,10 @@
<xsl:template match="all_etypes">
<xsl:for-each select= "$i//type">
<pre>
- <span class="bold_code">
+ <code class="erlang_repl">
<xsl:apply-templates select="typedecl"/>
- </span><xsl:text>
-</xsl:text>
+ </code><xsl:text>
+ </xsl:text>
</pre>
</xsl:for-each>
</xsl:template>
@@ -598,6 +598,7 @@
<body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000">
<div id="container">
+ <script id="js1" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/jquery-2.0.3.min.js"/>
<script id="js" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/flipmenu.js"/>
<script id="js2" type="text/javascript" src="{$topdocdir}/js/erlresolvelinks.js"></script>
<script language="JavaScript" type="text/javascript">
@@ -925,30 +926,26 @@
<!-- Note -->
<xsl:template match="note">
<xsl:param name="chapnum"/>
- <div class="note">
- <div class="label">Note</div>
- <div class="content">
- <p>
- <xsl:apply-templates>
- <xsl:with-param name="chapnum" select="$chapnum"/>
- </xsl:apply-templates>
- </p>
- </div>
+ <div class="alert alert-info">
+ <h4>Note</h4>
+ <p>
+ <xsl:apply-templates>
+ <xsl:with-param name="chapnum" select="$chapnum"/>
+ </xsl:apply-templates>
+ </p>
</div>
</xsl:template>
<!-- Warning -->
<xsl:template match="warning">
<xsl:param name="chapnum"/>
- <div class="warning">
- <div class="label">Warning</div>
- <div class="content">
- <p>
- <xsl:apply-templates>
- <xsl:with-param name="chapnum" select="$chapnum"/>
- </xsl:apply-templates>
- </p>
- </div>
+ <div class="alert alert-error">
+ <h4>Warning</h4>
+ <p>
+ <xsl:apply-templates>
+ <xsl:with-param name="chapnum" select="$chapnum"/>
+ </xsl:apply-templates>
+ </p>
</div>
</xsl:template>
@@ -983,7 +980,7 @@
<xsl:variable name="codenum">
<xsl:number level="any" from="chapter" count="code"/>
</xsl:variable>
- <div class="example"><pre><xsl:apply-templates/></pre></div>
+ <pre><code class="erlang_repl"><xsl:apply-templates/></code></pre>
</xsl:template>
<!-- Pre -->
@@ -992,7 +989,7 @@
<xsl:variable name="codenum">
<xsl:number level="any" from="chapter" count="code"/>
</xsl:variable>
- <div class="example"><pre><xsl:apply-templates/></pre></div>
+ <pre><code class="erlang_repl"><xsl:apply-templates/></code></pre>
</xsl:template>
@@ -2139,6 +2136,7 @@
<body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000">
<div id="container">
+ <script id="js1" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/jquery-2.0.3.min.js"/>
<script id="js" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/flipmenu.js"/>
<script id="js2" type="text/javascript" src="{$topdocdir}/js/erlresolvelinks.js"></script>
@@ -2194,6 +2192,7 @@
<body bgcolor="white" text="#000000" link="#0000ff" vlink="#ff00ff" alink="#ff0000">
<div id="container">
+ <script id="js1" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/jquery-2.0.3.min.js"/>
<script id="js" type="text/javascript" language="JavaScript" src="{$topdocdir}/js/flipmenu/flipmenu.js"/>
<script id="js2" type="text/javascript" src="{$topdocdir}/js/erlresolvelinks.js"></script>
diff --git a/lib/erl_interface/src/legacy/erl_eterm.c b/lib/erl_interface/src/legacy/erl_eterm.c
index 7ca4f430de..636d26b24b 100644
--- a/lib/erl_interface/src/legacy/erl_eterm.c
+++ b/lib/erl_interface/src/legacy/erl_eterm.c
@@ -686,7 +686,7 @@ int erl_length(const ETERM *ep)
return n;
}
-
+
/***********************************************************************
* I o l i s t f u n c t i o n s
*
diff --git a/lib/erl_interface/test/all_SUITE_data/ei_runner.c b/lib/erl_interface/test/all_SUITE_data/ei_runner.c
index 205f911e38..cdf32b48c4 100644
--- a/lib/erl_interface/test/all_SUITE_data/ei_runner.c
+++ b/lib/erl_interface/test/all_SUITE_data/ei_runner.c
@@ -77,7 +77,7 @@ run_tests(char* argv0, TestCase test_cases[], unsigned number)
}
}
-
+
/***********************************************************************
*
* R e a d i n g p a c k e t s
@@ -182,7 +182,7 @@ char *read_packet(int *len)
return io_buf;
}
-
+
/***********************************************************************
* S e n d i n g r e p l i e s
*
diff --git a/lib/erl_interface/test/all_SUITE_data/runner.c b/lib/erl_interface/test/all_SUITE_data/runner.c
index a474c17722..038d651275 100644
--- a/lib/erl_interface/test/all_SUITE_data/runner.c
+++ b/lib/erl_interface/test/all_SUITE_data/runner.c
@@ -78,7 +78,7 @@ run_tests(char* argv0, TestCase test_cases[], unsigned number)
}
}
-
+
/***********************************************************************
*
* R e a d i n g p a c k e t s
@@ -188,7 +188,7 @@ char *read_packet(int *len)
return io_buf;
}
-
+
/***********************************************************************
* S e n d i n g r e p l i e s
*
diff --git a/lib/erl_interface/test/ei_accept_SUITE.erl b/lib/erl_interface/test/ei_accept_SUITE.erl
index 48469e68dc..642809ea7a 100644
--- a/lib/erl_interface/test/ei_accept_SUITE.erl
+++ b/lib/erl_interface/test/ei_accept_SUITE.erl
@@ -155,7 +155,7 @@ start_einode(Einode, N, Host, Port) ->
ok.
-
+
%%% Interface functions for ei (erl_interface) functions.
ei_connect_init(P, Num, Cookie, Creation) ->
diff --git a/lib/erl_interface/test/erl_connect_SUITE.erl b/lib/erl_interface/test/erl_connect_SUITE.erl
index bd54013402..c8becc760c 100644
--- a/lib/erl_interface/test/erl_connect_SUITE.erl
+++ b/lib/erl_interface/test/erl_connect_SUITE.erl
@@ -106,7 +106,7 @@ erl_reg_send(Config) when is_list(Config) ->
?line runner:recv_eot(P),
ok.
-
+
%%% Interface functions for erl_interface functions.
erl_connect_init(P, Num, Cookie, Creation) ->
diff --git a/lib/erl_interface/test/erl_eterm_SUITE.erl b/lib/erl_interface/test/erl_eterm_SUITE.erl
index 10a27e48e3..100e9b6f68 100644
--- a/lib/erl_interface/test/erl_eterm_SUITE.erl
+++ b/lib/erl_interface/test/erl_eterm_SUITE.erl
@@ -108,7 +108,7 @@ end_per_group(_GroupName, Config) ->
Config.
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%% 1. B a s i c t e s t s
@@ -196,7 +196,7 @@ t_erl_free_compound(Config) when is_list(Config) ->
?line runner:test(?t_erl_free_compound),
ok.
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%% 2. C o n s t r u c t i n g t e r m s
@@ -521,7 +521,7 @@ t_erl_cons(Config) when is_list(Config) ->
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%% 3. E x t r a c t i n g & i n f o f u n c t i o n s
@@ -669,7 +669,7 @@ t_erl_element(Config) when is_list(Config) ->
ok.
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%% 4. I / O l i s t f u n c t i o n s
@@ -894,7 +894,7 @@ iolist_to_string(Port, Term) ->
'NULL' -> 'NULL'
end.
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%% 5. M i s c e l l a n o u s T e s t s
diff --git a/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c b/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
index 80d7f69520..94959187b9 100644
--- a/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
+++ b/lib/erl_interface/test/erl_eterm_SUITE_data/eterm_test.c
@@ -269,7 +269,7 @@ TESTCASE(t_erl_free_compound)
report(1);
}
-
+
/***********************************************************************
*
* 2. C o n s t r u c t i n g t e r m s
@@ -1047,7 +1047,7 @@ TESTCASE(t_erl_cons)
-
+
/***********************************************************************
*
* 3. E x t r a c t i n g & i n f o f u n c t i o n s
@@ -1296,7 +1296,7 @@ TESTCASE(extractor_macros)
}
-
+
/***********************************************************************
*
* 4. I / O l i s t f u n c t i o n s
@@ -1393,7 +1393,7 @@ TESTCASE(t_erl_iolist_to_string)
}
}
-
+
/***********************************************************************
*
* 5. M i s c e l l a n o u s T e s t s
diff --git a/lib/eunit/src/eunit_proc.erl b/lib/eunit/src/eunit_proc.erl
index ec7d93fd48..03d1a18321 100644
--- a/lib/eunit/src/eunit_proc.erl
+++ b/lib/eunit/src/eunit_proc.erl
@@ -643,11 +643,11 @@ io_request({get_until, _Prompt, _M, _F, _As}, Buf) ->
io_request({setopts, _Opts}, Buf) ->
{ok, Buf};
io_request(getopts, Buf) ->
- {error, {error, enotsup}, Buf};
+ {{error, enotsup}, Buf};
io_request({get_geometry,columns}, Buf) ->
- {error, {error, enotsup}, Buf};
+ {{error, enotsup}, Buf};
io_request({get_geometry,rows}, Buf) ->
- {error, {error, enotsup}, Buf};
+ {{error, enotsup}, Buf};
io_request({requests, Reqs}, Buf) ->
io_requests(Reqs, {ok, Buf});
io_request(_, Buf) ->
@@ -657,3 +657,10 @@ io_requests([R | Rs], {ok, Buf}) ->
io_requests(Rs, io_request(R, Buf));
io_requests(_, Result) ->
Result.
+
+-ifdef(TEST).
+io_error_test_() ->
+ [?_assertMatch({error, enotsup}, io:getopts()),
+ ?_assertMatch({error, enotsup}, io:columns()),
+ ?_assertMatch({error, enotsup}, io:rows())].
+-endif.
diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl
index cc021625d5..a2463d32e8 100644
--- a/lib/eunit/src/eunit_surefire.erl
+++ b/lib/eunit/src/eunit_surefire.erl
@@ -174,7 +174,7 @@ handle_cancel(group, Data, St) ->
setup_failed -> "fixture setup ";
cleanup_failed -> "fixture cleanup "
end
- ++ io_lib:format("~p", [proplists:get_value(id, Data)]),
+ ++ io_lib:format("~w", [proplists:get_value(id, Data)]),
Desc = format_desc(proplists:get_value(desc, Data)),
TestCase = #testcase{
name = Name, description = Desc,
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index d1243b2325..d7d8a878c5 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -671,8 +671,9 @@ t_solve_remote(?function(Domain, Range), ET, R, C) ->
{RT2, RR2} = t_solve_remote(Range, ET, R, C),
{?function(RT1, RT2), RR1 ++ RR2};
t_solve_remote(?list(Types, Term, Size), ET, R, C) ->
- {RT, RR} = t_solve_remote(Types, ET, R, C),
- {?list(RT, Term, Size), RR};
+ {RT1, RR1} = t_solve_remote(Types, ET, R, C),
+ {RT2, RR2} = t_solve_remote(Term, ET, R, C),
+ {?list(RT1, RT2, Size), RR1 ++ RR2};
t_solve_remote(?product(Types), ET, R, C) ->
{RL, RR} = list_solve_remote(Types, ET, R, C),
{?product(RL), RR};
@@ -1349,8 +1350,8 @@ t_maybe_improper_list() ->
t_maybe_improper_list(_Content, ?unit) -> ?none;
t_maybe_improper_list(?unit, _Termination) -> ?none;
t_maybe_improper_list(Content, Termination) ->
- %% Safety check
- true = t_is_subtype(t_nil(), Termination),
+ %% Safety check: would be nice to have but does not work with remote types
+ %% true = t_is_subtype(t_nil(), Termination),
?list(Content, Termination, ?unknown_qual).
-spec t_is_maybe_improper_list(erl_type()) -> boolean().
@@ -1365,8 +1366,8 @@ t_is_maybe_improper_list(_) -> false.
%% t_improper_list(?unit, _Termination) -> ?none;
%% t_improper_list(_Content, ?unit) -> ?none;
%% t_improper_list(Content, Termination) ->
-%% %% Safety check
-%% false = t_is_subtype(t_nil(), Termination),
+%% %% Safety check: would be nice to have but does not work with remote types
+%% %% false = t_is_subtype(t_nil(), Termination),
%% ?list(Content, Termination, ?any).
-spec lift_list_to_pos_empty(erl_type()) -> erl_type().
diff --git a/lib/ic/c_src/Makefile.in b/lib/ic/c_src/Makefile.in
index 6e65f06114..ed860ab73b 100644
--- a/lib/ic/c_src/Makefile.in
+++ b/lib/ic/c_src/Makefile.in
@@ -132,10 +132,8 @@ docs:
_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR))
$(LIBRARY): $(OBJ_FILES)
- $(ar_verbose)
- -$(AR) $(AR_OUT) $@ $(OBJ_FILES)
- $(ranlib_verbose)
- -$(RANLIB) $@
+ -$(V_AR) $(AR_OUT) $@ $(OBJ_FILES)
+ -$(V_RANLIB) $@
$(OBJDIR)/%.o: %.c
$(V_CC) $(CC_FLAGS) -c -o $@ $(ALL_CFLAGS) $<
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index d9a27e7d1e..db68cc3116 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2012</year>
+ <year>2004</year><year>2013</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -440,7 +440,10 @@ apply(Module, Function, [ReplyInfo | Args])
<v>Profile = profile() | pid() (when started <c>stand_alone</c>)</v>
</type>
<desc>
- <p>Cancels an asynchronous HTTP-request. </p>
+ <p>Cancels an asynchronous HTTP-request. Note this does not guarantee
+ that the request response will not be delivered, as it is asynchronous the
+ the request may already have been completed when the cancellation arrives.
+ </p>
<marker id="set_options"></marker>
</desc>
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index 4d7023a8e9..da9bbdd1ec 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -208,16 +208,8 @@ cancel_request(RequestId) ->
cancel_request(RequestId, Profile)
when is_atom(Profile) orelse is_pid(Profile) ->
?hcrt("cancel request", [{request_id, RequestId}, {profile, Profile}]),
- ok = httpc_manager:cancel_request(RequestId, profile_name(Profile)),
- receive
- %% If the request was already fulfilled throw away the
- %% answer as the request has been canceled.
- {http, {RequestId, _}} ->
- ok
- after 0 ->
- ok
- end.
-
+ httpc_manager:cancel_request(RequestId, profile_name(Profile)).
+
%%--------------------------------------------------------------------------
%% set_options(Options) -> ok | {error, Reason}
@@ -241,14 +233,7 @@ set_options(Options, Profile) when is_atom(Profile) orelse is_pid(Profile) ->
?hcrt("set options", [{options, Options}, {profile, Profile}]),
case validate_options(Options) of
{ok, Opts} ->
- try
- begin
- httpc_manager:set_options(Opts, profile_name(Profile))
- end
- catch
- exit:{noproc, _} ->
- {error, inets_not_started}
- end;
+ httpc_manager:set_options(Opts, profile_name(Profile));
{error, Reason} ->
{error, Reason}
end.
@@ -343,8 +328,6 @@ store_cookies(SetCookieHeaders, Url, Profile)
ok
end
catch
- exit:{noproc, _} ->
- {error, {not_started, Profile}};
error:{badmatch, Bad} ->
{error, {parse_failed, Bad}}
end.
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 55794f57dc..80c8b2439e 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -32,7 +32,7 @@
start_link/4,
%% connect_and_send/2,
send/2,
- cancel/3,
+ cancel/2,
stream_next/1,
info/1
]).
@@ -117,8 +117,8 @@ send(Request, Pid) ->
%% Description: Cancels a request. Intended to be called by the httpc
%% manager process.
%%--------------------------------------------------------------------
-cancel(RequestId, Pid, From) ->
- cast({cancel, RequestId, From}, Pid).
+cancel(RequestId, Pid) ->
+ cast({cancel, RequestId}, Pid).
%%--------------------------------------------------------------------
@@ -400,19 +400,17 @@ handle_call(info, _, State) ->
%% handle_keep_alive_queue/2 on the other hand will just skip the
%% request as if it was never issued as in this case the request will
%% not have been sent.
-handle_cast({cancel, RequestId, From},
+handle_cast({cancel, RequestId},
#state{request = #request{id = RequestId} = Request,
profile_name = ProfileName,
canceled = Canceled} = State) ->
?hcrv("cancel current request", [{request_id, RequestId},
{profile, ProfileName},
{canceled, Canceled}]),
- httpc_manager:request_canceled(RequestId, ProfileName, From),
- ?hcrv("canceled", []),
{stop, normal,
State#state{canceled = [RequestId | Canceled],
request = Request#request{from = answer_sent}}};
-handle_cast({cancel, RequestId, From},
+handle_cast({cancel, RequestId},
#state{profile_name = ProfileName,
request = #request{id = CurrId},
canceled = Canceled} = State) ->
@@ -420,8 +418,6 @@ handle_cast({cancel, RequestId, From},
{curr_req_id, CurrId},
{profile, ProfileName},
{canceled, Canceled}]),
- httpc_manager:request_canceled(RequestId, ProfileName, From),
- ?hcrv("canceled", []),
{noreply, State#state{canceled = [RequestId | Canceled]}};
handle_cast(stream_next, #state{session = Session} = State) ->
@@ -521,19 +517,12 @@ handle_info({Proto, _Socket, Data},
activate_once(Session),
{noreply, State#state{mfa = NewMFA}}
catch
- exit:_Exit ->
- ?hcrd("data processing exit", [{exit, _Exit}]),
+ _:_Reason ->
+ ?hcrd("data processing exit", [{exit, _Reason}]),
ClientReason = {could_not_parse_as_http, Data},
ClientErrMsg = httpc_response:error(Request, ClientReason),
NewState = answer_request(Request, ClientErrMsg, State),
- {stop, normal, NewState};
- error:_Error ->
- ?hcrd("data processing error", [{error, _Error}]),
- ClientReason = {could_not_parse_as_http, Data},
- ClientErrMsg = httpc_response:error(Request, ClientReason),
- NewState = answer_request(Request, ClientErrMsg, State),
{stop, normal, NewState}
-
end,
?hcri("data processed", [{final_result, FinalResult}]),
FinalResult;
@@ -1165,7 +1154,7 @@ handle_http_body(Body, #state{headers = Headers,
handle_response(#state{status = new} = State) ->
?hcrd("handle response - status = new", []),
- handle_response(try_to_enable_pipeline_or_keep_alive(State));
+ handle_response(check_persistent(State));
handle_response(#state{request = Request,
status = Status,
@@ -1440,39 +1429,22 @@ is_keep_alive_enabled_server(_,_) ->
is_keep_alive_connection(Headers, #session{client_close = ClientClose}) ->
(not ((ClientClose) orelse httpc_response:is_server_closing(Headers))).
-try_to_enable_pipeline_or_keep_alive(
- #state{session = Session,
- request = #request{method = Method},
+check_persistent(
+ #state{session = #session{type = Type} = Session,
status_line = {Version, _, _},
headers = Headers,
- profile_name = ProfileName} = State) ->
- ?hcrd("try to enable pipeline or keep-alive",
- [{version, Version},
- {headers, Headers},
- {session, Session}]),
+ profile_name = ProfileName} = State) ->
case is_keep_alive_enabled_server(Version, Headers) andalso
- is_keep_alive_connection(Headers, Session) of
+ is_keep_alive_connection(Headers, Session) of
true ->
- case (is_pipeline_enabled_client(Session) andalso
- httpc_request:is_idempotent(Method)) of
- true ->
- insert_session(Session, ProfileName),
- State#state{status = pipeline};
- false ->
- insert_session(Session, ProfileName),
- %% Make sure type is keep_alive in session
- %% as it in this case might be pipeline
- NewSession = Session#session{type = keep_alive},
- State#state{status = keep_alive,
- session = NewSession}
- end;
+ mark_persistent(ProfileName, Session),
+ State#state{status = Type};
false ->
State#state{status = close}
end.
answer_request(#request{id = RequestId, from = From} = Request, Msg,
- #state{session = Session,
- timers = Timers,
+ #state{timers = Timers,
profile_name = ProfileName} = State) ->
?hcrt("answer request", [{request, Request}, {msg, Msg}]),
httpc_response:send(From, Msg),
@@ -1482,19 +1454,14 @@ answer_request(#request{id = RequestId, from = From} = Request, Msg,
Timer = {RequestId, TimerRef},
cancel_timer(TimerRef, {timeout, Request#request.id}),
httpc_manager:request_done(RequestId, ProfileName),
- NewSession = maybe_make_session_available(ProfileName, Session),
Timers2 = Timers#timers{request_timers = lists:delete(Timer,
RequestTimers)},
State#state{request = Request#request{from = answer_sent},
- session = NewSession,
timers = Timers2}.
-maybe_make_session_available(ProfileName,
- #session{available = false} = Session) ->
- update_session(ProfileName, Session, #session.available, true),
- Session#session{available = true};
-maybe_make_session_available(_ProfileName, Session) ->
- Session.
+mark_persistent(ProfileName, Session) ->
+ update_session(ProfileName, Session, #session.persistent, true),
+ Session#session{persistent = true}.
cancel_timers(#timers{request_timers = ReqTmrs, queue_timer = QTmr}) ->
cancel_timer(QTmr, timeout_queue),
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index 30e2742e9d..d5b3dd2a2a 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -143,8 +143,8 @@
%% true | false
%% This will be true, when a response has been received for
- %% the first request. See type above.
- available = false
+ %% the first request and the server has not closed the connection
+ persistent = false
}).
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index c45dcab802..a3ed371e61 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2002-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
@@ -29,7 +29,6 @@
start_link/3,
request/2,
cancel_request/2,
- request_canceled/3,
request_done/2,
retry_request/2,
redirect_request/2,
@@ -144,22 +143,7 @@ redirect_request(Request, ProfileName) ->
%%--------------------------------------------------------------------
cancel_request(RequestId, ProfileName) ->
- call(ProfileName, {cancel_request, RequestId}).
-
-
-%%--------------------------------------------------------------------
-%% Function: request_canceled(RequestId, ProfileName) -> ok
-%% RequestId - ref()
-%% ProfileName = atom()
-%%
-%% Description: Confirms that a request has been canceld. Intended to
-%% be called by the httpc handler process.
-%%--------------------------------------------------------------------
-
-request_canceled(RequestId, ProfileName, From) ->
- gen_server:reply(From, ok),
- cast(ProfileName, {request_canceled, RequestId}).
-
+ cast(ProfileName, {cancel_request, RequestId}).
%%--------------------------------------------------------------------
%% Function: request_done(RequestId, ProfileName) -> ok
@@ -467,33 +451,13 @@ do_init(ProfileName, CookiesDir) ->
%%--------------------------------------------------------------------
handle_call({request, Request}, _, State) ->
?hcri("request", [{request, Request}]),
- case (catch handle_request(Request, State)) of
+ case (catch handle_request(Request, State, false)) of
{reply, Msg, NewState} ->
{reply, Msg, NewState};
Error ->
{stop, Error, httpc_response:error(Request, Error), State}
end;
-handle_call({cancel_request, RequestId}, From,
- #state{handler_db = HandlerDb} = State) ->
- ?hcri("cancel_request", [{request_id, RequestId}]),
- case ets:lookup(HandlerDb, RequestId) of
- [] ->
- %% The request has allready compleated make sure
- %% it is deliverd to the client process queue so
- %% it can be thrown away by httpc:cancel_request
- %% This delay is hopfully a temporary workaround.
- %% Note that it will not not delay the manager,
- %% only the client that called httpc:cancel_request
- timer:apply_after(?DELAY, gen_server, reply, [From, ok]),
- {noreply, State};
- [{_, Pid, _}] ->
- httpc_handler:cancel(RequestId, Pid, From),
- {noreply,
- State#state{cancel =
- [{RequestId, Pid, From} | State#state.cancel]}}
- end;
-
handle_call(reset_cookies, _, #state{cookie_db = CookieDb} = State) ->
?hcrv("reset cookies", []),
httpc_cookie:reset_db(CookieDb),
@@ -547,7 +511,7 @@ handle_cast({retry_or_redirect_request, {Time, Request}},
{noreply, State};
handle_cast({retry_or_redirect_request, Request}, State) ->
- case (catch handle_request(Request, State)) of
+ case (catch handle_request(Request, State, true)) of
{reply, {ok, _}, NewState} ->
{noreply, NewState};
Error ->
@@ -555,19 +519,19 @@ handle_cast({retry_or_redirect_request, Request}, State) ->
{stop, Error, State}
end;
-handle_cast({request_canceled, RequestId}, State) ->
- ?hcrv("request canceled", [{request_id, RequestId}]),
- ets:delete(State#state.handler_db, RequestId),
- case lists:keysearch(RequestId, 1, State#state.cancel) of
- {value, Entry = {RequestId, _, From}} ->
- ?hcrt("found in cancel", [{from, From}]),
- {noreply,
- State#state{cancel = lists:delete(Entry, State#state.cancel)}};
- Else ->
- ?hcrt("not found in cancel", [{else, Else}]),
- {noreply, State}
+handle_cast({cancel_request, RequestId},
+ #state{handler_db = HandlerDb} = State) ->
+ case ets:lookup(HandlerDb, RequestId) of
+ [] ->
+ %% Request already compleated nothing to
+ %% cancel
+ {noreply, State};
+ [{_, Pid, _}] ->
+ httpc_handler:cancel(RequestId, Pid),
+ ets:delete(State#state.handler_db, RequestId),
+ {noreply, State}
end;
-
+
handle_cast({request_done, RequestId}, State) ->
?hcrv("request done", [{request_id, RequestId}]),
ets:delete(State#state.handler_db, RequestId),
@@ -629,22 +593,8 @@ handle_info({'EXIT', _, _}, State) ->
%% Handled in DOWN
{noreply, State};
handle_info({'DOWN', _, _, Pid, _}, State) ->
- ets:match_delete(State#state.handler_db, {'_', Pid, '_'}),
-
- %% If there where any canceled request, handled by the
- %% the process that now has terminated, the
- %% cancelation can be viewed as sucessfull!
- NewCanceldList =
- lists:foldl(fun(Entry = {_, HandlerPid, From}, Acc) ->
- case HandlerPid of
- Pid ->
- gen_server:reply(From, ok),
- lists:delete(Entry, Acc);
- _ ->
- Acc
- end
- end, State#state.cancel, State#state.cancel),
- {noreply, State#state{cancel = NewCanceldList}};
+ ets:match_delete(State#state.handler_db, {'_', Pid, '_'}),
+ {noreply, State};
handle_info(Info, State) ->
Report = io_lib:format("Unknown message in "
"httpc_manager:handle_info ~p~n", [Info]),
@@ -774,7 +724,7 @@ get_handler_info(Tab) ->
handle_request(#request{settings =
#http_options{version = "HTTP/0.9"}} = Request,
- State) ->
+ State, _) ->
%% Act as an HTTP/0.9 client that does not know anything
%% about persistent connections
@@ -787,7 +737,7 @@ handle_request(#request{settings =
handle_request(#request{settings =
#http_options{version = "HTTP/1.0"}} = Request,
- State) ->
+ State, _) ->
%% Act as an HTTP/1.0 client that does not
%% use persistent connections
@@ -798,13 +748,13 @@ handle_request(#request{settings =
start_handler(NewRequest#request{headers = NewHeaders}, State),
{reply, {ok, NewRequest#request.id}, State};
-handle_request(Request, State = #state{options = Options}) ->
+handle_request(Request, State = #state{options = Options}, Retry) ->
NewRequest = handle_cookies(generate_request_id(Request), State),
SessionType = session_type(Options),
case select_session(Request#request.method,
Request#request.address,
- Request#request.scheme, SessionType, State) of
+ Request#request.scheme, SessionType, State, Retry) of
{ok, HandlerPid} ->
pipeline_or_keep_alive(NewRequest, HandlerPid, State);
no_connection ->
@@ -828,6 +778,7 @@ start_handler(#request{id = Id,
#state{profile_name = ProfileName,
handler_db = HandlerDb,
options = Options}) ->
+ ClientClose = httpc_request:is_client_closing(Request#request.headers),
{ok, Pid} =
case is_inets_manager() of
true ->
@@ -838,13 +789,18 @@ start_handler(#request{id = Id,
end,
HandlerInfo = {Id, Pid, From},
ets:insert(HandlerDb, HandlerInfo),
+ insert_session(#session{id = {Request#request.address, Pid},
+ scheme = Request#request.scheme,
+ client_close = ClientClose,
+ type = session_type(Options)
+ }, ProfileName),
erlang:monitor(process, Pid).
select_session(Method, HostPort, Scheme, SessionType,
#state{options = #options{max_pipeline_length = MaxPipe,
max_keep_alive_length = MaxKeepAlive},
- session_db = SessionDb}) ->
+ session_db = SessionDb}, Retry) ->
?hcrd("select session", [{session_type, SessionType},
{max_pipeline_length, MaxPipe},
{max_keep_alive_length, MaxKeepAlive}]),
@@ -857,19 +813,29 @@ select_session(Method, HostPort, Scheme, SessionType,
%% client_close, scheme and type specified.
%% The fields id (part of: HandlerPid) and queue_length
%% specified.
- Pattern = #session{id = {HostPort, '$1'},
- client_close = false,
- scheme = Scheme,
- queue_length = '$2',
- type = SessionType,
- available = true,
- _ = '_'},
+ Pattern = case (Retry andalso SessionType == pipeline) of
+ true ->
+ #session{id = {HostPort, '$1'},
+ client_close = false,
+ scheme = Scheme,
+ queue_length = '$2',
+ type = SessionType,
+ persistent = true,
+ _ = '_'};
+ false ->
+ #session{id = {HostPort, '$1'},
+ client_close = false,
+ scheme = Scheme,
+ queue_length = '$2',
+ type = SessionType,
+ _ = '_'}
+ end,
%% {'_', {HostPort, '$1'}, false, Scheme, '_', '$2', SessionTyp},
Candidates = ets:match(SessionDb, Pattern),
?hcrd("select session", [{host_port, HostPort},
{scheme, Scheme},
{type, SessionType},
- {candidates, Candidates}]),
+ {candidates, Candidates}]),
select_session(Candidates, MaxKeepAlive, MaxPipe, SessionType);
false ->
no_connection
diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl
index b3ca13e2fe..27446ca7fe 100644
--- a/lib/inets/src/http_server/httpd_conf.erl
+++ b/lib/inets/src/http_server/httpd_conf.erl
@@ -798,6 +798,8 @@ store({log_format, LogFormat}, _ConfigList)
store({server_tokens, ServerTokens} = Entry, _ConfigList) ->
Server = server(ServerTokens),
{ok, [Entry, {server, Server}]};
+store({keep_alive_timeout, KeepAliveTimeout}, _ConfigList) ->
+ {ok, {keep_alive_timeout, KeepAliveTimeout * 1000}};
store(ConfigListEntry, _ConfigList) ->
{ok, ConfigListEntry}.
diff --git a/lib/inets/src/http_server/httpd_log.erl b/lib/inets/src/http_server/httpd_log.erl
index a34435e0e8..7ff73669f9 100644
--- a/lib/inets/src/http_server/httpd_log.erl
+++ b/lib/inets/src/http_server/httpd_log.erl
@@ -39,14 +39,21 @@
Size :: 0 | pos_integer() | string()) ->
{Log :: atom() | pid(), Entry :: string()} | term() .
-access_entry(Log, NoLog, Info, RFC931, AuthUser, Date, StatusCode, SizeStr)
- when is_list(SizeStr) ->
+%% Somethime the size in the form of the content_length is put here, which
+%% is actually in the form of a string
+%% So it can either be the size as an integer, the size as a string
+%% or, worst case scenario, bytes.
+access_entry(Log, NoLog, Info, RFC931, AuthUser, Date, StatusCode,
+ SizeStrOrBytes)
+ when is_list(SizeStrOrBytes) ->
Size =
- case (catch list_to_integer(SizeStr)) of
+ case (catch list_to_integer(SizeStrOrBytes)) of
I when is_integer(I) ->
+ %% This is from using the content_length (which is a string)
I;
_ ->
- SizeStr % This is better then nothing
+ %% This is better than nothing
+ httpd_util:flatlength(SizeStrOrBytes)
end,
access_entry(Log, NoLog, Info, RFC931, AuthUser, Date, StatusCode, Size);
access_entry(Log, NoLog,
diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl
index cb20159794..ea7a17e40d 100644
--- a/lib/inets/src/http_server/httpd_request_handler.erl
+++ b/lib/inets/src/http_server/httpd_request_handler.erl
@@ -267,9 +267,9 @@ handle_info({ssl_error, _, _} = Reason, State) ->
{stop, Reason, State};
%% Timeouts
-handle_info(timeout, #state{mod = ModData, mfa = {_, parse, _}} = State) ->
- error_log("No request received on keep-alive connection "
- "before server side timeout", ModData),
+handle_info(timeout, #state{mfa = {_, parse, _}} = State) ->
+ %% error_log("No request received on keep-alive connection "
+ %% "before server side timeout", ModData),
%% No response should be sent!
{stop, normal, State#state{response_sent = true}};
handle_info(timeout, #state{mod = ModData} = State) ->
@@ -316,7 +316,10 @@ terminate(normal, State) ->
do_terminate(State);
terminate(Reason, #state{response_sent = false, mod = ModData} = State) ->
httpd_response:send_status(ModData, 500, none),
- error_log(httpd_util:reason_phrase(500), ModData),
+ ReasonStr =
+ lists:flatten(io_lib:format("~s - ~p",
+ [httpd_util:reason_phrase(500), Reason])),
+ error_log(ReasonStr, ModData),
terminate(Reason, State#state{response_sent = true, mod = ModData});
terminate(_Reason, State) ->
do_terminate(State).
diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl
index a45b04f275..0895729d05 100644
--- a/lib/inets/src/http_server/httpd_response.erl
+++ b/lib/inets/src/http_server/httpd_response.erl
@@ -23,9 +23,10 @@
is_disable_chunked_send/1, cache_headers/2]).
-export([map_status_code/2]).
--include("httpd.hrl").
--include("http_internal.hrl").
--include("httpd_internal.hrl").
+-include_lib("inets/src/inets_app/inets_internal.hrl").
+-include_lib("inets/include/httpd.hrl").
+-include_lib("inets/src/http_lib/http_internal.hrl").
+-include_lib("inets/src/http_server/httpd_internal.hrl").
-define(VMODULE,"RESPONSE").
@@ -35,7 +36,7 @@ generate_and_send_response(#mod{init_data =
#init_data{peername = {_,"unknown"}}}) ->
ok;
generate_and_send_response(#mod{config_db = ConfigDB} = ModData) ->
- Modules = httpd_util:lookup(ConfigDB,modules, ?DEFAULT_MODS),
+ Modules = httpd_util:lookup(ConfigDB, modules, ?DEFAULT_MODS),
case traverse_modules(ModData, Modules) of
done ->
ok;
@@ -68,16 +69,7 @@ traverse_modules(ModData,[]) ->
{proceed,ModData#mod.data};
traverse_modules(ModData,[Module|Rest]) ->
?hdrd("traverse modules", [{callback_module, Module}]),
- case (catch apply(Module, do, [ModData])) of
- {'EXIT', Reason} ->
- String =
- lists:flatten(
- io_lib:format("traverse exit from apply: ~p:do => ~n~p",
- [Module, Reason])),
- report_error(mod_log, ModData#mod.config_db, String),
- report_error(mod_disk_log, ModData#mod.config_db, String),
- send_status(ModData, 500, none),
- done;
+ try apply(Module, do, [ModData]) of
done ->
?hdrt("traverse modules - done", []),
done;
@@ -87,6 +79,19 @@ traverse_modules(ModData,[Module|Rest]) ->
{proceed, NewData} ->
?hdrt("traverse modules - proceed", [{new_data, NewData}]),
traverse_modules(ModData#mod{data = NewData}, Rest)
+ catch
+ T:E ->
+ String =
+ lists:flatten(
+ io_lib:format("module traverse failed: ~p:do => "
+ "~n Error Type: ~p"
+ "~n Error: ~p"
+ "~n Stack trace: ~p",
+ [Module, T, E, ?STACK()])),
+ report_error(mod_log, ModData#mod.config_db, String),
+ report_error(mod_disk_log, ModData#mod.config_db, String),
+ send_status(ModData, 500, none),
+ done
end.
%% send_status %%
diff --git a/lib/inets/src/http_server/mod_cgi.erl b/lib/inets/src/http_server/mod_cgi.erl
index f1b73810e6..d933b0a4ba 100644
--- a/lib/inets/src/http_server/mod_cgi.erl
+++ b/lib/inets/src/http_server/mod_cgi.erl
@@ -131,9 +131,9 @@ store({script_nocache, Value} = Conf, _)
{ok, Conf};
store({script_nocache, Value}, _) ->
{error, {wrong_type, {script_nocache, Value}}};
-store({script_timeout, Value} = Conf, _)
+store({script_timeout, Value}, _)
when is_integer(Value), Value >= 0 ->
- {ok, Conf};
+ {ok, {script_timeout, Value * 1000}};
store({script_timeout, Value}, _) ->
{error, {wrong_type, {script_timeout, Value}}}.
@@ -238,7 +238,7 @@ send_request_body_to_script(ModData, Port) ->
end.
deliver_webpage(#mod{config_db = Db} = ModData, Port) ->
- Timeout = cgi_timeout(Db),
+ Timeout = script_timeout(Db),
case receive_headers(Port, httpd_cgi, parse_headers,
[<<>>, [], []], Timeout) of
{Headers, Body} ->
@@ -341,8 +341,8 @@ script_elements(#mod{method = "PUT", entity_body = Body}, _) ->
script_elements(_, _) ->
[].
-cgi_timeout(Db) ->
- httpd_util:lookup(Db, cgi_timeout, ?DEFAULT_CGI_TIMEOUT).
+script_timeout(Db) ->
+ httpd_util:lookup(Db, script_timeout, ?DEFAULT_CGI_TIMEOUT).
%% Convert error to printable string
%%
diff --git a/lib/inets/src/http_server/mod_head.erl b/lib/inets/src/http_server/mod_head.erl
index c346fd4d23..02b8485b25 100644
--- a/lib/inets/src/http_server/mod_head.erl
+++ b/lib/inets/src/http_server/mod_head.erl
@@ -42,6 +42,10 @@ do(Info) ->
%% A response has been sent! Nothing to do about it!
{already_sent, _StatusCode, _Size} ->
{proceed,Info#mod.data};
+ {response, Header, _Body} -> %% New way
+ {proceed,
+ lists:keyreplace(response, 1, Info#mod.data,
+ {response, Header, nobody})};
%% A response has been generated!
{_StatusCode, _Response} ->
{proceed,Info#mod.data}
diff --git a/lib/inets/src/inets_app/inets_internal.hrl b/lib/inets/src/inets_app/inets_internal.hrl
index e56af3b59d..06843f2275 100644
--- a/lib/inets/src/inets_app/inets_internal.hrl
+++ b/lib/inets/src/inets_app/inets_internal.hrl
@@ -21,6 +21,8 @@
-ifndef(inets_internal_hrl).
-define(inets_internal_hrl, true).
+-define(STACK(), erlang:get_stacktrace()).
+
%% Various trace macros
-define(report(Severity, Label, Service, Content),
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 0c35f284f7..818edc12ac 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -277,9 +277,6 @@ trace(Config) when is_list(Config) ->
pipeline(Config) when is_list(Config) ->
Request = {url(group_name(Config), "/dummy.html", Config), []},
{ok, _} = httpc:request(get, Request, [], [], pipeline),
-
- %% Make sure pipeline session is registerd
- test_server:sleep(4000),
keep_alive_requests(Request, pipeline).
%%--------------------------------------------------------------------
@@ -287,9 +284,6 @@ pipeline(Config) when is_list(Config) ->
persistent_connection(Config) when is_list(Config) ->
Request = {url(group_name(Config), "/dummy.html", Config), []},
{ok, _} = httpc:request(get, Request, [], [], persistent),
-
- %% Make sure pipeline session is registerd
- test_server:sleep(4000),
keep_alive_requests(Request, persistent).
%%-------------------------------------------------------------------------
@@ -311,13 +305,8 @@ async(Config) when is_list(Config) ->
{ok, NewRequestId} =
httpc:request(get, Request, [], [{sync, false}]),
- ok = httpc:cancel_request(NewRequestId),
- receive
- {http, {NewRequestId, _}} ->
- ct:fail(http_cancel_request_failed)
- after 3000 ->
- ok
- end.
+ ok = httpc:cancel_request(NewRequestId).
+
%%-------------------------------------------------------------------------
save_to_file() ->
[{doc, "Test to save the http body to a file"}].
@@ -1149,7 +1138,7 @@ receive_replys([ID|IDs]) ->
{http, {ID, {{_, 200, _}, [_|_], _}}} ->
receive_replys(IDs);
{http, {Other, {{_, 200, _}, [_|_], _}}} ->
- ct:fail({recived_canceld_id, Other})
+ ct:pal({recived_canceld_id, Other})
end.
%% Perform a synchronous stop
diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl
index b1fe373cff..2d06f3e70c 100644
--- a/lib/inets/test/httpd_basic_SUITE.erl
+++ b/lib/inets/test/httpd_basic_SUITE.erl
@@ -38,7 +38,9 @@ all() ->
erl_script_nocache_opt,
script_nocache,
escaped_url_in_error_body,
- slowdose
+ script_timeout,
+ slowdose,
+ keep_alive_timeout
].
groups() ->
@@ -80,16 +82,19 @@ DUMMY
DummyFile = filename:join([PrivDir,"dummy.html"]),
CgiDir = filename:join(PrivDir, "cgi-bin"),
ok = file:make_dir(CgiDir),
- Cgi = case test_server:os_type() of
- {win32, _} ->
- "printenv.bat";
- _ ->
- "printenv.sh"
- end,
- inets_test_lib:copy_file(Cgi, DataDir, CgiDir),
- AbsCgi = filename:join([CgiDir, Cgi]),
- {ok, FileInfo} = file:read_file_info(AbsCgi),
- ok = file:write_file_info(AbsCgi, FileInfo#file_info{mode = 8#00755}),
+ {CgiPrintEnv, CgiSleep} = case test_server:os_type() of
+ {win32, _} ->
+ {"printenv.bat", "cgi_sleep.exe"};
+ _ ->
+ {"printenv.sh", "cgi_sleep"}
+ end,
+ lists:foreach(
+ fun(Cgi) ->
+ inets_test_lib:copy_file(Cgi, DataDir, CgiDir),
+ AbsCgi = filename:join([CgiDir, Cgi]),
+ {ok, FileInfo} = file:read_file_info(AbsCgi),
+ ok = file:write_file_info(AbsCgi, FileInfo#file_info{mode = 8#00755})
+ end, [CgiPrintEnv, CgiSleep]),
{ok, Fd} = file:open(DummyFile, [write]),
ok = file:write(Fd, Dummy),
ok = file:close(Fd),
@@ -100,7 +105,8 @@ DUMMY
{document_root, PrivDir},
{bind_address, "localhost"}],
- [{httpd_conf, HttpdConf}, {cgi_dir, CgiDir}, {cgi_script, Cgi} | Config].
+ [{httpd_conf, HttpdConf}, {cgi_dir, CgiDir},
+ {cgi_printenv, CgiPrintEnv}, {cgi_sleep, CgiSleep} | Config].
%%--------------------------------------------------------------------
%% Function: end_per_suite(Config) -> _
@@ -235,7 +241,7 @@ script_nocache(Config) when is_list(Config) ->
verify_script_nocache(Config, CgiNoCache, EsiNoCache, CgiOption, EsiOption) ->
HttpdConf = ?config(httpd_conf, Config),
- CgiScript = ?config(cgi_script, Config),
+ CgiScript = ?config(cgi_printenv, Config),
CgiDir = ?config(cgi_dir, Config),
{ok, Pid} = inets:start(httpd, [{port, 0},
{script_alias,
@@ -363,6 +369,63 @@ escaped_url_in_error_body(Config) when is_list(Config) ->
inets:stop(httpd, Pid),
tsp("escaped_url_in_error_body -> done"),
ok.
+
+
+%%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
+
+keep_alive_timeout(doc) ->
+ ["Test the keep_alive_timeout option"];
+keep_alive_timeout(suite) ->
+ [];
+keep_alive_timeout(Config) when is_list(Config) ->
+ HttpdConf = ?config(httpd_conf, Config),
+ {ok, Pid} = inets:start(httpd, [{port, 0}, {keep_alive, true}, {keep_alive_timeout, 2} | HttpdConf]),
+ Info = httpd:info(Pid),
+ Port = proplists:get_value(port, Info),
+ _Address = proplists:get_value(bind_address, Info),
+ {ok, S} = gen_tcp:connect("localhost", Port, []),
+ receive
+ after 3000 ->
+ {error, closed} = gen_tcp:send(S, "hey")
+ end,
+ inets:stop(httpd, Pid).
+
+%%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
+
+script_timeout(doc) ->
+ ["Test the httpd script_timeout option"];
+script_timeout(suite) ->
+ [];
+script_timeout(Config) when is_list(Config) ->
+ verify_script_timeout(Config, 20, 200),
+ verify_script_timeout(Config, 5, 403),
+ ok.
+
+verify_script_timeout(Config, ScriptTimeout, StatusCode) ->
+ HttpdConf = ?config(httpd_conf, Config),
+ CgiScript = ?config(cgi_sleep, Config),
+ CgiDir = ?config(cgi_dir, Config),
+ {ok, Pid} = inets:start(httpd, [{port, 0},
+ {script_alias,
+ {"/cgi-bin/", CgiDir ++ "/"}},
+ {script_timeout, ScriptTimeout}
+ | HttpdConf]),
+ Info = httpd:info(Pid),
+ Port = proplists:get_value(port, Info),
+ Address = proplists:get_value(bind_address, Info),
+ ok = httpd_test_lib:verify_request(ip_comm, Address, Port, node(),
+ "GET /cgi-bin/" ++ CgiScript ++
+ " HTTP/1.0\r\n\r\n",
+ [{statuscode, StatusCode},
+ {version, "HTTP/1.0"}]),
+ inets:stop(httpd, Pid).
+
+
+%%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
+
slowdose(doc) ->
["Testing minimum bytes per second option"];
slowdose(Config) when is_list(Config) ->
diff --git a/lib/inets/test/httpd_basic_SUITE_data/Makefile.src b/lib/inets/test/httpd_basic_SUITE_data/Makefile.src
new file mode 100644
index 0000000000..9da2ed583f
--- /dev/null
+++ b/lib/inets/test/httpd_basic_SUITE_data/Makefile.src
@@ -0,0 +1,14 @@
+CC = @CC@
+LD = @LD@
+CFLAGS = @CFLAGS@ -I@erl_include@ @DEFS@
+CROSSLDFLAGS = @CROSSLDFLAGS@
+
+PROGS = cgi_sleep@exe@
+
+all: $(PROGS)
+
+cgi_sleep@exe@: cgi_sleep@obj@
+ $(LD) $(CROSSLDFLAGS) -o cgi_sleep cgi_sleep@obj@ @LIBS@
+
+cgi_sleep@obj@: cgi_sleep.c
+ $(CC) -c -o cgi_sleep@obj@ $(CFLAGS) cgi_sleep.c
diff --git a/lib/inets/test/httpd_basic_SUITE_data/cgi_sleep.c b/lib/inets/test/httpd_basic_SUITE_data/cgi_sleep.c
new file mode 100644
index 0000000000..126bb23987
--- /dev/null
+++ b/lib/inets/test/httpd_basic_SUITE_data/cgi_sleep.c
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#ifdef __WIN32__
+#include <windows.h>
+#include <fcntl.h>
+#include <io.h>
+#else
+#include <unistd.h>
+#endif
+
+int main(void)
+{
+ unsigned int seconds = 10;
+
+#ifdef __WIN32__
+ Sleep(seconds * 1000);
+ _setmode(_fileno(stdout), _O_BINARY);
+#else
+ sleep(seconds);
+#endif
+
+ printf("Content-type: text/plain\r\n\r\n");
+ printf("Slept for %u seconds.\r\n", seconds);
+ exit(EXIT_SUCCESS);
+}
diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml
index 7ea58fffff..33f1c20608 100644
--- a/lib/kernel/doc/src/gen_sctp.xml
+++ b/lib/kernel/doc/src/gen_sctp.xml
@@ -322,7 +322,7 @@
<p>
Branch off an existing association <anno>Assoc</anno>
in a socket <anno>Socket</anno> of type <c>seqpacket</c>
- (one-to-may style) into
+ (one-to-many style) into
a new socket <anno>NewSocket</anno> of type <c>stream</c>
(one-to-one style).
</p>
diff --git a/lib/kernel/doc/src/rpc.xml b/lib/kernel/doc/src/rpc.xml
index b01ff16c85..67fdccb734 100644
--- a/lib/kernel/doc/src/rpc.xml
+++ b/lib/kernel/doc/src/rpc.xml
@@ -185,7 +185,7 @@
{Mod, Bin, File} = code:get_object_code(Mod),
%% and load it on all nodes including this one
-{ResL, _} = rpc:multicall(code, load_binary, [Mod, Bin, File,]),
+{ResL, _} = rpc:multicall(code, load_binary, [Mod, File, Bin]),
%% and then maybe check the ResL list.</code>
</desc>
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index 58d84ae924..067e07304d 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -423,7 +423,11 @@ error_string(9) ->
error_string(10) ->
"Cookie Received While Shutting Down";
error_string(11) ->
+ "Restart of an Association with New Addresses";
+error_string(12) ->
"User Initiated Abort";
+error_string(13) ->
+ "Protocol Violation";
%% For more info on principal SCTP error codes: phone +44 7981131933
error_string(N) when is_integer(N) ->
unknown_error;
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 27f085c3aa..d4c78505da 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -120,6 +120,17 @@
'addr' | 'broadaddr' | 'dstaddr' |
'mtu' | 'netmask' | 'flags' |'hwaddr'.
+-type if_getopt_result() ::
+ {'addr', ip_address()} |
+ {'broadaddr', ip_address()} |
+ {'dstaddr', ip_address()} |
+ {'mtu', non_neg_integer()} |
+ {'netmask', ip_address()} |
+ {'flags', ['up' | 'down' | 'broadcast' | 'no_broadcast' |
+ 'pointtopoint' | 'no_pointtopoint' |
+ 'running' | 'multicast' | 'loopback']} |
+ {'hwaddr', ether_address()}.
+
-type address_family() :: 'inet' | 'inet6'.
-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'.
-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'.
@@ -266,13 +277,13 @@ getiflist() ->
-spec ifget(Socket :: socket(),
Name :: string() | atom(),
Opts :: [if_getopt()]) ->
- {'ok', [if_setopt()]} | {'error', posix()}.
+ {'ok', [if_getopt_result()]} | {'error', posix()}.
ifget(Socket, Name, Opts) ->
prim_inet:ifget(Socket, Name, Opts).
-spec ifget(Name :: string() | atom(), Opts :: [if_getopt()]) ->
- {'ok', [if_setopt()]} | {'error', posix()}.
+ {'ok', [if_getopt_result()]} | {'error', posix()}.
ifget(Name, Opts) ->
withsocket(fun(S) -> prim_inet:ifget(S, Name, Opts) end).
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index 96c1e3d83d..12fe0a7637 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 2.16.3
+KERNEL_VSN = 2.16.4
diff --git a/lib/observer/doc/src/ttb.xml b/lib/observer/doc/src/ttb.xml
index 4e63aecbf2..1453bbdf10 100644
--- a/lib/observer/doc/src/ttb.xml
+++ b/lib/observer/doc/src/ttb.xml
@@ -105,8 +105,9 @@ ttb:p(all, call)</code>
<v>Nodes = atom() | [atom()] | all | existing | new</v>
<v>Opts = Opt | [Opt]</v>
<v>Opt = {file,Client} | {handler, FormatHandler} | {process_info,PI} |
- shell | {shell, ShellSpec} | {timer, TimerSpec} | {overload, {MSec, Module, Function}}
- | {flush, MSec} | resume | {resume, FetchTimeout}</v>
+ shell | {shell, ShellSpec} | {timer, TimerSpec} |
+ {overload_check, {MSec, Module, Function}} |
+ {flush, MSec} | resume | {resume, FetchTimeout}</v>
<v>TimerSpec = MSec | {MSec, StopOpts}</v>
<v>MSec = FetchTimeout = integer()</v>
<v>Module = Function = atom() </v>
@@ -158,7 +159,7 @@ ttb:p(all, call)</code>
network communication are always present. The timer starts after
<c>ttb:p/2</c> is issued, so you can set up your trace patterns before.
</p>
- <p>The <c>overload</c> option allows to enable overload
+ <p>The <c>overload_check</c> option allows to enable overload
checking on the nodes under trace. <c>Module:Function(check)</c>
is performed each <c>MSec</c> milliseconds. If the check returns
<c>true</c>, the tracing is disabled on a given node.<br/>
diff --git a/lib/orber/test/multi_ORB_SUITE.erl b/lib/orber/test/multi_ORB_SUITE.erl
index 3c1ffd59d3..41a309ff16 100644
--- a/lib/orber/test/multi_ORB_SUITE.erl
+++ b/lib/orber/test/multi_ORB_SUITE.erl
@@ -75,8 +75,6 @@
close_connections_local_interface_ctx_override_api/1,
ssl_1_multi_orber_generation_3_api/1, ssl_2_multi_orber_generation_3_api/1,
ssl_reconfigure_generation_3_api/1,
- ssl_1_multi_orber_generation_3_api_old/1, ssl_2_multi_orber_generation_3_api_old/1,
- ssl_reconfigure_generation_3_api_old/1,
close_connections_alt_iiop_addr_api/1, close_connections_multiple_profiles_api/1]).
@@ -137,13 +135,10 @@ cases() ->
setup_multi_connection_timeout_attempts_api,
setup_multi_connection_timeout_random_api,
ssl_1_multi_orber_api,
- ssl_1_multi_orber_generation_3_api_old,
ssl_1_multi_orber_generation_3_api,
ssl_2_multi_orber_api,
- ssl_2_multi_orber_generation_3_api_old,
ssl_2_multi_orber_generation_3_api,
ssl_reconfigure_api,
- ssl_reconfigure_generation_3_api_old,
ssl_reconfigure_generation_3_api].
%%-----------------------------------------------------------------
@@ -155,10 +150,7 @@ init_per_testcase(TC,Config)
TC =:= ssl_reconfigure_api ->
init_ssl(Config);
init_per_testcase(TC,Config)
- when TC =:= ssl_1_multi_orber_generation_3_api_old;
- TC =:= ssl_2_multi_orber_generation_3_api_old;
- TC =:= ssl_reconfigure_generation_3_api_old;
- TC =:= ssl_1_multi_orber_generation_3_api;
+ when TC =:= ssl_1_multi_orber_generation_3_api;
TC =:= ssl_2_multi_orber_generation_3_api;
TC =:= ssl_reconfigure_generation_3_api ->
init_ssl_3(Config);
@@ -1632,22 +1624,6 @@ ssl_1_multi_orber_api(_Config) ->
ssl_suite(ServerOptions, ClientOptions).
-ssl_1_multi_orber_generation_3_api_old(doc) -> ["SECURE MULTI ORB API tests (SSL depth 1)",
- "This case set up two secure orbs and test if they can",
- "communicate. The case also test to access one of the",
- "secure orbs which must raise a NO_PERMISSION exception."];
-ssl_1_multi_orber_generation_3_api_old(suite) -> [];
-ssl_1_multi_orber_generation_3_api_old(_Config) ->
-
- ServerOptions = orber_test_lib:get_options_old(iiop_ssl, server,
- 1, [{ssl_generation, 3},
- {iiop_ssl_port, 0}]),
- ClientOptions = orber_test_lib:get_options_old(iiop_ssl, client,
- 1, [{ssl_generation, 3},
- {iiop_ssl_port, 0}]),
- ssl_suite(ServerOptions, ClientOptions).
-
-
ssl_1_multi_orber_generation_3_api(doc) -> ["SECURE MULTI ORB API tests (SSL depth 1)",
"This case set up two secure orbs and test if they can",
"communicate. The case also test to access one of the",
@@ -1681,22 +1657,6 @@ ssl_2_multi_orber_api(_Config) ->
ssl_suite(ServerOptions, ClientOptions).
-ssl_2_multi_orber_generation_3_api_old(doc) -> ["SECURE MULTI ORB API tests (SSL depth 2)",
- "This case set up two secure orbs and test if they can",
- "communicate. The case also test to access one of the",
- "secure orbs which must raise a NO_PERMISSION exception."];
-ssl_2_multi_orber_generation_3_api_old(suite) -> [];
-ssl_2_multi_orber_generation_3_api_old(_Config) ->
-
- ServerOptions = orber_test_lib:get_options_old(iiop_ssl, server,
- 2, [{ssl_generation, 3},
- {iiop_ssl_port, 0}]),
- ClientOptions = orber_test_lib:get_options_old(iiop_ssl, client,
- 2, [{ssl_generation, 3},
- {iiop_ssl_port, 0}]),
- ssl_suite(ServerOptions, ClientOptions).
-
-
ssl_2_multi_orber_generation_3_api(doc) -> ["SECURE MULTI ORB API tests (SSL depth 2)",
"This case set up two secure orbs and test if they can",
"communicate. The case also test to access one of the",
@@ -1724,11 +1684,6 @@ ssl_reconfigure_api(_Config) ->
ssl_reconfigure_old([]).
-ssl_reconfigure_generation_3_api_old(doc) -> ["SECURE MULTI ORB API tests (SSL depth 2)",
- "This case set up two secure orbs and test if they can",
- "communicate. The case also test to access one of the",
- "secure orbs which must raise a NO_PERMISSION exception."];
-ssl_reconfigure_generation_3_api_old(suite) -> [];
ssl_reconfigure_generation_3_api_old(_Config) ->
ssl_reconfigure_old([{ssl_generation, 3}]).
diff --git a/lib/orber/test/orber_nat_SUITE.erl b/lib/orber/test/orber_nat_SUITE.erl
index ee31b162c2..a21bd4d499 100644
--- a/lib/orber/test/orber_nat_SUITE.erl
+++ b/lib/orber/test/orber_nat_SUITE.erl
@@ -57,7 +57,6 @@
nat_ip_address_local/1, nat_ip_address_local_local/1,
nat_iiop_port/1, nat_iiop_port_local/1,
nat_iiop_port_local_local/1,
- nat_iiop_ssl_port_old/1, nat_iiop_ssl_port_local_old/1,
nat_iiop_ssl_port/1, nat_iiop_ssl_port_local/1]).
@@ -93,8 +92,6 @@ cases() ->
nat_iiop_port_local,
nat_ip_address_local_local,
nat_iiop_port_local_local,
- nat_iiop_ssl_port_old,
- nat_iiop_ssl_port_local_old,
nat_iiop_ssl_port,
nat_iiop_ssl_port_local].
@@ -103,9 +100,7 @@ cases() ->
%%-----------------------------------------------------------------
init_per_testcase(TC, Config)
when TC =:= nat_iiop_ssl_port;
- TC =:= nat_iiop_ssl_port_local;
- TC =:= nat_iiop_ssl_port_old;
- TC =:= nat_iiop_ssl_port_local_old ->
+ TC =:= nat_iiop_ssl_port_local ->
case ?config(crypto_started, Config) of
true ->
case orber_test_lib:ssl_version() of
@@ -291,106 +286,6 @@ nat_iiop_port_local_local(_Config) ->
%% API tests for ORB to ORB, ssl security depth 1
%%-----------------------------------------------------------------
-nat_iiop_ssl_port_old(doc) -> ["SECURE MULTI ORB API tests (SSL depth 1)",
- "Make sure NAT works for SSL"];
-nat_iiop_ssl_port_old(suite) -> [];
-nat_iiop_ssl_port_old(_Config) ->
-
- IP = orber_test_lib:get_host(),
- ServerOptions = orber_test_lib:get_options_old(iiop_ssl, server,
- 1, [{iiop_ssl_port, 0},
- {flags, ?ORB_ENV_ENABLE_NAT},
- {ip_address, IP}]),
- ClientOptions = orber_test_lib:get_options_old(iiop_ssl, client,
- 1, [{iiop_ssl_port, 0}]),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node(ServerOptions)),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- SSLServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_ssl_port, []),
- NATSSLServerPort = SSLServerPort+1,
- {ok, Ref} = ?match({ok, _},
- orber_test_lib:remote_apply(ServerNode, orber,
- add_listen_interface,
- [IP, ssl, NATSSLServerPort])),
- orber_test_lib:remote_apply(ServerNode, orber_env, configure_override,
- [nat_iiop_ssl_port,
- {local, NATSSLServerPort, [{4001, 43}]}]),
-
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node(ClientOptions)),
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [ssl])),
-
- IOR1 = ?match(#'IOP_IOR'{},
- orber_test_lib:remote_apply(ClientNode, corba,
- string_to_object,
- ["corbaname::1.2@"++IP++":"++
- integer_to_list(ServerPort)++"/NameService#mamba"])),
-
- ?match({'external', {_IP, _Port, _ObjectKey, _Counter, _TP,
- #host_data{protocol = ssl,
- ssl_data = #'SSLIOP_SSL'{port = NATSSLServerPort}}}},
- iop_ior:get_key(IOR1)),
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- uninstall_test_data,
- [ssl])),
- ?match(ok,
- orber_test_lib:remote_apply(ServerNode, orber,
- remove_listen_interface, [Ref])),
- ok.
-
-nat_iiop_ssl_port_local_old(doc) -> ["SECURE MULTI ORB API tests (SSL depth 1)",
- "Make sure NAT works for SSL"];
-nat_iiop_ssl_port_local_old(suite) -> [];
-nat_iiop_ssl_port_local_old(_Config) ->
-
- IP = orber_test_lib:get_host(),
- ServerOptions = orber_test_lib:get_options_old(iiop_ssl, server,
- 1, [{iiop_ssl_port, 0},
- {flags,
- (?ORB_ENV_LOCAL_INTERFACE bor
- ?ORB_ENV_ENABLE_NAT)},
- {ip_address, IP}]),
- ClientOptions = orber_test_lib:get_options_old(iiop_ssl, client,
- 1, [{iiop_ssl_port, 0}]),
- {ok, ServerNode, _ServerHost} =
- ?match({ok,_,_}, orber_test_lib:js_node(ServerOptions)),
- ServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_port, []),
- SSLServerPort = orber_test_lib:remote_apply(ServerNode, orber, iiop_ssl_port, []),
- NATSSLServerPort = SSLServerPort+1,
- {ok, Ref} = ?match({ok, _},
- orber_test_lib:remote_apply(ServerNode, orber,
- add_listen_interface,
- [IP, ssl, NATSSLServerPort])),
- orber_test_lib:remote_apply(ServerNode, orber_env, configure_override,
- [nat_iiop_ssl_port,
- {local, NATSSLServerPort, [{NATSSLServerPort, NATSSLServerPort}]}]),
-
- {ok, ClientNode, _ClientHost} =
- ?match({ok,_,_}, orber_test_lib:js_node(ClientOptions)),
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- install_test_data,
- [ssl])),
-
- IOR1 = ?match(#'IOP_IOR'{},
- orber_test_lib:remote_apply(ClientNode, corba,
- string_to_object,
- ["corbaname::1.2@"++IP++":"++
- integer_to_list(ServerPort)++"/NameService#mamba"])),
-
- ?match({'external', {_IP, _Port, _ObjectKey, _Counter, _TP,
- #host_data{protocol = ssl,
- ssl_data = #'SSLIOP_SSL'{port = NATSSLServerPort}}}},
- iop_ior:get_key(IOR1)),
- ?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
- uninstall_test_data,
- [ssl])),
- ?match(ok,
- orber_test_lib:remote_apply(ServerNode, orber,
- remove_listen_interface, [Ref])),
- ok.
-
nat_iiop_ssl_port(doc) -> ["SECURE MULTI ORB API tests (SSL depth 1)",
"Make sure NAT works for SSL"];
diff --git a/lib/os_mon/src/memsup.erl b/lib/os_mon/src/memsup.erl
index a1b8591c8c..b178732fae 100644
--- a/lib/os_mon/src/memsup.erl
+++ b/lib/os_mon/src/memsup.erl
@@ -721,20 +721,19 @@ reply(Pending, MemUsage, SysMemUsage) ->
%% get_memory_usage(OS) -> {Alloc, Total}
%% Darwin:
-%% Uses vm_stat command. This appears to lie about the page size in
-%% Mac OS X 10.2.2 - the pages given are based on 4000 bytes, but
-%% the vm_stat command tells us that it is 4096...
+%% Uses vm_stat command.
get_memory_usage({unix,darwin}) ->
Str1 = os:cmd("/usr/bin/vm_stat"),
-
- {[Free], Str2} = fread_value("Pages free:~d.", Str1),
- {[Active], Str3} = fread_value("Pages active:~d.", Str2),
- {[Inactive], Str4} = fread_value("Pages inactive:~d.", Str3),
- {[_], Str5} = fread_value("Pages speculative:~d.", Str4),
+ PageSize = 4096,
+
+ {[Free], Str2} = fread_value("Pages free:~d.", Str1),
+ {[Active], Str3} = fread_value("Pages active:~d.", Str2),
+ {[Inactive], Str4} = fread_value("Pages inactive:~d.", Str3),
+ {[Speculative], Str5} = fread_value("Pages speculative:~d.", Str4),
{[Wired], _} = fread_value("Pages wired down:~d.", Str5),
- NMemUsed = (Wired + Active + Inactive) * 4000,
- NMemTotal = NMemUsed + Free * 4000,
+ NMemUsed = (Wired + Active + Inactive) * PageSize,
+ NMemTotal = NMemUsed + (Free + Speculative) * PageSize,
{NMemUsed,NMemTotal};
%% FreeBSD: Look in /usr/include/sys/vmmeter.h for the format of struct
diff --git a/lib/public_key/asn1/OTP-PKIX.asn1 b/lib/public_key/asn1/OTP-PKIX.asn1
index 911a156d6c..8d3c76adf5 100644
--- a/lib/public_key/asn1/OTP-PKIX.asn1
+++ b/lib/public_key/asn1/OTP-PKIX.asn1
@@ -252,7 +252,17 @@ domainComponent ATTRIBUTE-TYPE-AND-VALUE-CLASS ::= {
emailAddress ATTRIBUTE-TYPE-AND-VALUE-CLASS ::= {
ID id-emailAddress
- TYPE EmailAddress }
+ TYPE EmailAddress } -- this is currently not used when decoding
+ -- The decoding and mapping between ID and Type is done in the code
+ -- in module publickey_cert_records via the function attribute_type
+ -- To be more forgiving and compatible with other SSL implementations
+ -- regarding how to handle and sometimes accept incorrect certificates
+ -- we define and use the type below instead of emailAddress
+
+ OTP-emailAddress ::= CHOICE {
+ ia5String IA5String (SIZE (1..255)),
+ utf8String UTF8String (SIZE (1..255))
+}
--
-- Signature and Public Key Algorithms
diff --git a/lib/public_key/doc/src/using_public_key.xml b/lib/public_key/doc/src/using_public_key.xml
index 5d9f1536d9..450bd7e35f 100644
--- a/lib/public_key/doc/src/using_public_key.xml
+++ b/lib/public_key/doc/src/using_public_key.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="iso-8859-1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
@@ -90,7 +90,7 @@
[{'RSAPrivateKey',&lt;&lt;224,108,117,203,152,40,15,77,128,126,
221,195,154,249,85,208,202,251,109,
119,120,57,29,89,19,9,...&gt;&gt;,
- {"DES-EDE3-CBC",&lt;&lt;"k�e��p�L"&gt;&gt;}}]
+ {"DES-EDE3-CBC",&lt;&lt;"kÙeø¼pµL"&gt;&gt;}}]
</code>
@@ -350,7 +350,7 @@ ok</code>
<p> or </p>
- <code>1> PemBin = public_key:pem_entry_encode('SubjectPublicKeyInfo', RSAPubKey).
+ <code>1> PemEntry = public_key:pem_entry_encode('SubjectPublicKeyInfo', RSAPubKey).
{'SubjectPublicKeyInfo', &lt;&lt;48,92...&gt;&gt;, not_encrypted}
2> PemBin = public_key:pem_encode([PemEntry]).
diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl
index 0449129809..fdd89aa70d 100644
--- a/lib/public_key/src/pubkey_cert_records.erl
+++ b/lib/public_key/src/pubkey_cert_records.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -67,6 +67,15 @@ transform(#'AttributeTypeAndValue'{type=Id,value=Value0} = ATAV, Func) ->
{ok, {printableString, ASCCI}} ->
{ok, ASCCI}
end;
+ 'EmailAddress' when Func == decode ->
+ %% Workaround that some certificates break the ASN-1 spec
+ %% and encode emailAddress as utf8
+ case 'OTP-PUB-KEY':Func('OTP-emailAddress', Value0) of
+ {ok, {utf8String, Utf8Value}} ->
+ {ok, unicode:characters_to_list(Utf8Value)};
+ {ok, {ia5String, Ia5Value}} ->
+ {ok, Ia5Value}
+ end;
Type when is_atom(Type) -> 'OTP-PUB-KEY':Func(Type, Value0);
_UnknownType -> {ok, Value0}
end,
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index f8d167e770..d3e9bf7cf6 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -41,7 +41,7 @@ all() ->
{group, ssh_public_key_decode_encode},
encrypt_decrypt,
{group, sign_verify},
- pkix, pkix_countryname, pkix_path_validation,
+ pkix, pkix_countryname, pkix_emailaddress, pkix_path_validation,
pkix_iso_rsa_oid, pkix_iso_dsa_oid].
groups() ->
@@ -586,9 +586,9 @@ pkix(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
pkix_countryname() ->
- [{doc, "Test workaround for certs that code x509countryname as utf8"}].
+ [{doc, "Test workaround for certs that code x509countryname as utf8"}].
pkix_countryname(Config) when is_list(Config) ->
- Cert = incorrect_pkix_cert(),
+ Cert = incorrect_countryname_pkix_cert(),
OTPCert = public_key:pkix_decode_cert(Cert, otp),
TBSCert = OTPCert#'OTPCertificate'.tbsCertificate,
Issuer = TBSCert#'OTPTBSCertificate'.issuer,
@@ -597,6 +597,18 @@ pkix_countryname(Config) when is_list(Config) ->
check_countryname(Subj).
%%--------------------------------------------------------------------
+pkix_emailaddress() ->
+ [{doc, "Test workaround for certs that code emailAddress as utf8"}].
+pkix_emailaddress(Config) when is_list(Config) ->
+ Cert = incorrect_emailaddress_pkix_cert(),
+ OTPCert = public_key:pkix_decode_cert(Cert, otp),
+ TBSCert = OTPCert#'OTPCertificate'.tbsCertificate,
+ Issuer = TBSCert#'OTPTBSCertificate'.issuer,
+ Subj = TBSCert#'OTPTBSCertificate'.subject,
+ check_emailaddress(Issuer),
+ check_emailaddress(Subj).
+
+%%--------------------------------------------------------------------
pkix_path_validation() ->
[{doc, "Test PKIX path validation"}].
pkix_path_validation(Config) when is_list(Config) ->
@@ -710,10 +722,23 @@ do_check_countryname([#'AttributeTypeAndValue'{type = ?'id-at-countryName',
ok;
do_check_countryname([#'AttributeTypeAndValue'{type = ?'id-at-countryName',
value = Value}|_]) ->
- ct:fail({incorrect_cuntry_name, Value});
+ ct:fail({incorrect_country_name, Value});
do_check_countryname([_| Rest]) ->
do_check_countryname(Rest).
+check_emailaddress({rdnSequence,DirName}) ->
+ do_check_emailaddress(DirName).
+do_check_emailaddress([]) ->
+ ok;
+do_check_emailaddress([#'AttributeTypeAndValue'{type = ?'id-emailAddress',
+ value = "[email protected]"}|_]) ->
+ ok;
+do_check_emailaddress([#'AttributeTypeAndValue'{type = ?'id-emailAddress',
+ value = Value}|_]) ->
+ ct:fail({incorrect_email_address, Value});
+do_check_emailaddress([_| Rest]) ->
+ do_check_emailaddress(Rest).
+
check_entry_type(#'DSAPrivateKey'{}, 'DSAPrivateKey') ->
true;
check_entry_type(#'RSAPrivateKey'{}, 'RSAPrivateKey') ->
@@ -732,5 +757,8 @@ check_entry_type(_,_) ->
strip_ending_newlines(Bin) ->
string:strip(binary_to_list(Bin), right, 10).
-incorrect_pkix_cert() ->
+incorrect_countryname_pkix_cert() ->
<<48,130,5,186,48,130,4,162,160,3,2,1,2,2,7,7,250,61,63,6,140,137,48,13,6,9,42, 134,72,134,247,13,1,1,5,5,0,48,129,220,49,11,48,9,6,3,85,4,6,19,2,85,83,49, 16,48,14,6,3,85,4,8,19,7,65,114,105,122,111,110,97,49,19,48,17,6,3,85,4,7,19, 10,83,99,111,116,116,115,100,97,108,101,49,37,48,35,6,3,85,4,10,19,28,83,116, 97,114,102,105,101,108,100,32,84,101,99,104,110,111,108,111,103,105,101,115, 44,32,73,110,99,46,49,57,48,55,6,3,85,4,11,19,48,104,116,116,112,58,47,47,99, 101,114,116,105,102,105,99,97,116,101,115,46,115,116,97,114,102,105,101,108, 100,116,101,99,104,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121, 49,49,48,47,6,3,85,4,3,19,40,83,116,97,114,102,105,101,108,100,32,83,101,99, 117,114,101,32,67,101,114,116,105,102,105,99,97,116,105,111,110,32,65,117, 116,104,111,114,105,116,121,49,17,48,15,6,3,85,4,5,19,8,49,48,54,56,56,52,51, 53,48,30,23,13,49,48,49,48,50,51,48,49,51,50,48,53,90,23,13,49,50,49,48,50, 51,48,49,51,50,48,53,90,48,122,49,11,48,9,6,3,85,4,6,12,2,85,83,49,11,48,9,6, 3,85,4,8,12,2,65,90,49,19,48,17,6,3,85,4,7,12,10,83,99,111,116,116,115,100, 97,108,101,49,38,48,36,6,3,85,4,10,12,29,83,112,101,99,105,97,108,32,68,111, 109,97,105,110,32,83,101,114,118,105,99,101,115,44,32,73,110,99,46,49,33,48, 31,6,3,85,4,3,12,24,42,46,108,111,103,105,110,46,115,101,99,117,114,101,115, 101,114,118,101,114,46,110,101,116,48,130,1,34,48,13,6,9,42,134,72,134,247, 13,1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,185,136,240,80,141,36,124, 245,182,130,73,19,188,74,166,117,72,228,185,209,43,129,244,40,44,193,231,11, 209,12,234,88,43,142,1,162,48,122,17,95,230,105,171,131,12,147,46,204,36,80, 250,171,33,253,35,62,83,22,71,212,186,141,14,198,89,89,121,204,224,122,246, 127,110,188,229,162,67,95,6,74,231,127,99,131,7,240,85,102,203,251,50,58,58, 104,245,103,181,183,134,32,203,121,232,54,32,188,139,136,112,166,126,14,91, 223,153,172,164,14,61,38,163,208,215,186,210,136,213,143,70,147,173,109,217, 250,169,108,31,211,104,238,103,93,182,59,165,43,196,189,218,241,30,148,240, 109,90,69,176,194,52,116,173,151,135,239,10,209,179,129,192,102,75,11,25,168, 223,32,174,84,223,134,70,167,55,172,143,27,130,123,226,226,7,34,142,166,39, 48,246,96,231,150,84,220,106,133,193,55,95,159,227,24,249,64,36,1,142,171,16, 202,55,126,7,156,15,194,22,116,53,113,174,104,239,203,120,45,131,57,87,84, 163,184,27,83,57,199,91,200,34,43,98,61,180,144,76,65,170,177,2,3,1,0,1,163, 130,1,224,48,130,1,220,48,15,6,3,85,29,19,1,1,255,4,5,48,3,1,1,0,48,29,6,3, 85,29,37,4,22,48,20,6,8,43,6,1,5,5,7,3,1,6,8,43,6,1,5,5,7,3,2,48,14,6,3,85, 29,15,1,1,255,4,4,3,2,5,160,48,56,6,3,85,29,31,4,49,48,47,48,45,160,43,160, 41,134,39,104,116,116,112,58,47,47,99,114,108,46,115,116,97,114,102,105,101, 108,100,116,101,99,104,46,99,111,109,47,115,102,115,50,45,48,46,99,114,108, 48,83,6,3,85,29,32,4,76,48,74,48,72,6,11,96,134,72,1,134,253,110,1,7,23,2,48, 57,48,55,6,8,43,6,1,5,5,7,2,1,22,43,104,116,116,112,115,58,47,47,99,101,114, 116,115,46,115,116,97,114,102,105,101,108,100,116,101,99,104,46,99,111,109, 47,114,101,112,111,115,105,116,111,114,121,47,48,129,141,6,8,43,6,1,5,5,7,1, 1,4,129,128,48,126,48,42,6,8,43,6,1,5,5,7,48,1,134,30,104,116,116,112,58,47, 47,111,99,115,112,46,115,116,97,114,102,105,101,108,100,116,101,99,104,46,99, 111,109,47,48,80,6,8,43,6,1,5,5,7,48,2,134,68,104,116,116,112,58,47,47,99, 101,114,116,105,102,105,99,97,116,101,115,46,115,116,97,114,102,105,101,108, 100,116,101,99,104,46,99,111,109,47,114,101,112,111,115,105,116,111,114,121, 47,115,102,95,105,110,116,101,114,109,101,100,105,97,116,101,46,99,114,116, 48,31,6,3,85,29,35,4,24,48,22,128,20,73,75,82,39,209,27,188,242,161,33,106, 98,123,81,66,122,138,215,213,86,48,59,6,3,85,29,17,4,52,48,50,130,24,42,46, 108,111,103,105,110,46,115,101,99,117,114,101,115,101,114,118,101,114,46,110, 101,116,130,22,108,111,103,105,110,46,115,101,99,117,114,101,115,101,114,118, 101,114,46,110,101,116,48,29,6,3,85,29,14,4,22,4,20,138,233,191,208,157,203, 249,85,242,239,20,195,48,10,148,49,144,101,255,116,48,13,6,9,42,134,72,134, 247,13,1,1,5,5,0,3,130,1,1,0,82,31,121,162,49,50,143,26,167,202,143,61,71, 189,201,199,57,81,122,116,90,192,88,24,102,194,174,48,157,74,27,87,210,223, 253,93,3,91,150,109,120,1,110,27,11,200,198,141,222,246,14,200,71,105,41,138, 13,114,122,106,63,17,197,181,234,121,61,89,74,65,41,231,248,219,129,83,176, 219,55,107,55,211,112,98,38,49,69,77,96,221,108,123,152,12,210,159,157,141, 43,226,55,187,129,3,82,49,136,66,81,196,91,234,196,10,82,48,6,80,163,83,71, 127,102,177,93,209,129,26,104,2,84,24,255,248,161,3,244,169,234,92,122,110, 43,4,17,113,185,235,108,219,210,236,132,216,177,227,17,169,58,162,159,182, 162,93,160,229,200,9,163,229,110,121,240,168,232,14,91,214,188,196,109,210, 164,222,0,109,139,132,113,91,16,118,173,178,176,80,132,34,41,199,51,206,250, 224,132,60,115,192,94,107,163,219,212,226,225,65,169,148,108,213,46,174,173, 103,110,189,229,166,149,254,31,51,44,144,108,187,182,11,251,201,206,86,138, 208,59,51,86,132,235,81,225,88,34,190,8,184>>.
+
+incorrect_emailaddress_pkix_cert() ->
+ <<48,130,3,74,48,130,2,50,2,9,0,133,49,203,25,198,156,252,230,48,13,6,9,42,134, 72,134,247,13,1,1,5,5,0,48,103,49,11,48,9,6,3,85,4,6,19,2,65,85,49,19,48,17, 6,3,85,4,8,12,10,83,111,109,101,45,83,116,97,116,101,49,33,48,31,6,3,85,4,10, 12,24,73,110,116,101,114,110,101,116,32,87,105,100,103,105,116,115,32,80,116, 121,32,76,116,100,49,32,48,30,6,9,42,134,72,134,247,13,1,9,1,12,17,105,110, 118,97,108,105,100,64,101,109,97,105,108,46,99,111,109,48,30,23,13,49,51,49, 49,48,55,50,48,53,54,49,56,90,23,13,49,52,49,49,48,55,50,48,53,54,49,56,90, 48,103,49,11,48,9,6,3,85,4,6,19,2,65,85,49,19,48,17,6,3,85,4,8,12,10,83,111, 109,101,45,83,116,97,116,101,49,33,48,31,6,3,85,4,10,12,24,73,110,116,101, 114,110,101,116,32,87,105,100,103,105,116,115,32,80,116,121,32,76,116,100,49, 32,48,30,6,9,42,134,72,134,247,13,1,9,1,12,17,105,110,118,97,108,105,100,64, 101,109,97,105,108,46,99,111,109,48,130,1,34,48,13,6,9,42,134,72,134,247,13, 1,1,1,5,0,3,130,1,15,0,48,130,1,10,2,130,1,1,0,190,243,49,213,219,60,232,105, 1,127,126,9,130,15,60,190,78,100,148,235,246,223,21,91,238,200,251,84,55,212, 78,32,120,61,85,172,0,144,248,5,165,29,143,79,64,178,51,153,203,76,115,238, 192,49,173,37,121,203,89,62,157,13,181,166,30,112,154,40,202,140,104,211,157, 73,244,9,78,236,70,153,195,158,233,141,42,238,2,143,160,225,249,27,30,140, 151,176,43,211,87,114,164,108,69,47,39,195,123,185,179,219,28,218,122,53,83, 77,48,81,184,14,91,243,12,62,146,86,210,248,228,171,146,225,87,51,146,155, 116,112,238,212,36,111,58,41,67,27,6,61,61,3,84,150,126,214,121,57,38,12,87, 121,67,244,37,45,145,234,131,115,134,58,194,5,36,166,52,59,229,32,47,152,80, 237,190,58,182,248,98,7,165,198,211,5,31,231,152,116,31,108,71,218,64,188, 178,143,27,167,79,15,112,196,103,116,212,65,197,94,37,4,132,103,91,217,73, 223,207,185,7,153,221,240,232,31,44,102,108,82,83,56,242,210,214,74,71,246, 177,217,148,227,220,230,4,176,226,74,194,37,2,3,1,0,1,48,13,6,9,42,134,72, 134,247,13,1,1,5,5,0,3,130,1,1,0,89,247,141,154,173,123,123,203,143,85,28,79, 73,37,164,6,17,89,171,224,149,22,134,17,198,146,158,192,241,41,253,58,230, 133,71,189,43,66,123,88,15,242,119,227,249,99,137,61,200,54,161,0,177,167, 169,114,80,148,90,22,97,78,162,181,75,93,209,116,245,46,81,232,64,157,93,136, 52,57,229,113,197,218,113,93,42,161,213,104,205,137,30,144,183,58,10,98,47, 227,177,96,40,233,98,150,209,217,68,22,221,133,27,161,152,237,46,36,179,59, 172,97,134,194,205,101,137,71,192,57,153,20,114,27,173,233,166,45,56,0,61, 205,45,202,139,7,132,103,248,193,157,184,123,43,62,172,236,110,49,62,209,78, 249,83,219,133,1,213,143,73,174,16,113,143,189,41,84,60,128,222,30,177,104, 134,220,52,239,171,76,59,176,36,113,176,214,118,16,44,235,21,167,199,216,200, 76,219,142,248,13,70,145,205,216,230,226,148,97,223,216,179,68,209,222,63, 140,137,24,164,192,149,194,79,119,247,75,159,49,116,70,241,70,116,11,40,119, 176,157,36,160,102,140,255,34,248,25,231,136,59>>.
diff --git a/lib/sasl/src/sasl.erl b/lib/sasl/src/sasl.erl
index 989f99dc82..fdea6da13e 100644
--- a/lib/sasl/src/sasl.erl
+++ b/lib/sasl/src/sasl.erl
@@ -82,8 +82,8 @@ get_mf() ->
MaxB = get_mf_maxb(),
MaxF = get_mf_maxf(),
case {Dir, MaxB, MaxF} of
- {undefined,undefined,undefined} = R ->
- R;
+ {undefined,undefined,undefined} ->
+ undefined;
{undefined,_,_} ->
exit({missing_config, {sasl, error_logger_mf_dir}});
{_,undefined,_} ->
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index 141d3df38e..c1a51d57fc 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -53,8 +53,7 @@
returned by ssh:daemon/[1,2,3]</c></p>
<p><c>ssh_connection_ref() - opaque to the user
returned by ssh:connect/3</c></p>
- <p><c>ip_address() - {N1,N2,N3,N4} % IPv4 |
- {K1,K2,K3,K4,K5,K6,K7,K8} % IPv6</c></p>
+ <p><c>ip_address() - inet::ip_address()</c></p>
<p><c>subsystem_spec() = {subsystem_name(),
{channel_callback(), channel_init_args()}} </c></p>
<p><c>subsystem_name() = string() </c></p>
@@ -141,7 +140,7 @@
<p>Sets the preferred public key algorithm to use for user
authentication. If the the preferred algorithm fails for
some reason, the other algorithm is tried. The default is
- to try <c><![CDATA[ssh_rsa]]></c> first.</p>
+ to try <c><![CDATA['ssh-rsa']]></c> first.</p>
</item>
<tag><c><![CDATA[{pref_public_key_algs, list()}]]></c></tag>
<item>
@@ -181,10 +180,6 @@
<item>
<p>Allow an existing file descriptor to be used
(simply passed on to the transport protocol).</p></item>
- <tag><c><![CDATA[{ipv6_disabled, boolean()}]]></c></tag>
- <item>
- <p>Determines if SSH shall use IPv6 or not.</p>
- </item>
<tag><c><![CDATA[{rekey_limit, integer()}]]></c></tag>
<item>
<p>Provide, in bytes, when rekeying should be initiated,
@@ -202,8 +197,11 @@
Value}] </name>
<fsummary> Retrieves information about a connection. </fsummary>
<type>
- <v>Option = client_version | server_version | peer</v>
- <v>Value = term() </v>
+ <v>Option = client_version | server_version | user | peer | sockname </v>
+ <v>Value = [option_value()] </v>
+ <v>option_value() = {{Major::integer(), Minor::integer()}, VersionString::string()} | User::string() |
+ Peer::{inet:hostname(), {inet::ip_adress(), inet::port_number()}} |
+ Sockname::{inet::ip_adress(), inet::port_number()} () </v>
</type>
<desc>
<p> Retrieves information about a connection.
@@ -248,14 +246,15 @@
requested by the client. Default is to use the erlang shell:
<c><![CDATA[{shell, start, []}]]></c>
</item>
- <tag><c><![CDATA[{ssh_cli,{channel_callback(),
- channel_init_args()}}]]></c></tag>
+ <tag><c><![CDATA[{ssh_cli, {channel_callback(),
+ channel_init_args()} | no_cli}]]></c></tag>
<item>
- Provides your own cli implementation, i.e. a channel callback
+ Provides your own CLI implementation, i.e. a channel callback
module that implements a shell and command execution. Note
that you may customize the shell read-eval-print loop using the
option <c>shell</c> which is much less work than implementing
- your own cli channel.
+ your own CLI channel. If set to <c>no_cli</c> you will disable
+ CLI channels and only subsystem channels will be allowed.
</item>
<tag><c><![CDATA[{user_dir, String}]]></c></tag>
<item>
@@ -296,7 +295,7 @@
user. From a security perspective this option makes
the server very vulnerable.</p>
</item>
- <tag><c><![CDATA[{pwdfun, fun(User::string(), password::string() -> boolean()}]]></c></tag>
+ <tag><c><![CDATA[{pwdfun, fun(User::string(), password::string()) -> boolean()}]]></c></tag>
<item>
<p>Provide a function for password validation. This is called
with user and password as strings, and should return
@@ -313,26 +312,23 @@
<item>
<p>Allow an existing file-descriptor to be used
(simply passed on to the transport protocol).</p></item>
- <tag><c><![CDATA[{ip_v6_disabled, boolean()}]]></c></tag>
+ <tag><c><![CDATA[{failfun, fun(User::string(), PeerAddress::ip_address(), Reason::term()) -> _}]]></c></tag>
<item>
- <p>Determines if SSH shall use IPv6 or not (only used when
- HostAddress is set to any).</p></item>
- <tag><c><![CDATA[{failfun, fun()}]]></c></tag>
- <item>
- <p>Provide a fun() to implement your own logging when a user fails to authenticate.</p>
+ <p>Provide a fun to implement your own logging when a user fails to authenticate.</p>
</item>
- <tag><c><![CDATA[{connectfun, fun()}]]></c></tag>
+ <tag><c><![CDATA[{connectfun, fun(User::string(), PeerAddress::ip_address(), Method::string()) ->_}]]></c></tag>
<item>
- <p>Provide a fun() to implement your own logging when a user authenticates to the server.</p>
+ <p>Provide a fun to implement your own logging when a user authenticates to the server.</p>
</item>
- <tag><c><![CDATA[{disconnectfun, fun()}]]></c></tag>
+ <tag><c><![CDATA[{disconnectfun, fun(Reason:term()) -> _}]]></c></tag>
<item>
- <p>Provide a fun() to implement your own logging when a user disconnects from the server.</p>
+ <p>Provide a fun to implement your own logging when a user disconnects from the server.</p>
</item>
</taglist>
</desc>
</func>
+
<func>
<name>shell(Host) -> </name>
<name>shell(Host, Option) -> </name>
diff --git a/lib/ssh/doc/src/ssh_client_key_api.xml b/lib/ssh/doc/src/ssh_client_key_api.xml
index b9b1ec4efa..2fa06f8bf1 100644
--- a/lib/ssh/doc/src/ssh_client_key_api.xml
+++ b/lib/ssh/doc/src/ssh_client_key_api.xml
@@ -41,12 +41,14 @@
<p>Type definitions that are used more than once in this module
and/or abstractions to indicate the intended use of the data
- type:</p>
+ type. For more details on public key data types
+ see the <seealso marker="public_key:public_key_records"> public_key user's guide.</seealso>
+ </p>
<p> boolean() = true | false</p>
<p> string() = [byte()] </p>
<p> public_key() = #'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</p>
- <p> private_key() = #'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</p>
+ <p> private_key() = #'RSAPrivateKey'{} | #'DSAPrivateKey'{} | term()</p>
<p> public_key_algorithm() = 'ssh-rsa'| 'ssh-dss' | atom()</p>
</section>
diff --git a/lib/ssh/doc/src/ssh_server_key_api.xml b/lib/ssh/doc/src/ssh_server_key_api.xml
index c4562e1211..ee537f2f60 100644
--- a/lib/ssh/doc/src/ssh_server_key_api.xml
+++ b/lib/ssh/doc/src/ssh_server_key_api.xml
@@ -29,7 +29,7 @@
-behaviour(ssh_server_key_api).
</modulesummary>
<description>
- <p> Behaviour describing the API for an SSH server's public key handling.By implementing the callbacks defined
+ <p> Behaviour describing the API for an SSH server's public key handling. By implementing the callbacks defined
in this behavior it is possible to customize the SSH server's public key
handling. By default the SSH application implements this behavior
with help of the standard openssh files, see <seealso marker="SSH_app"> ssh(6)</seealso>.</p>
@@ -40,13 +40,15 @@
<p>Type definitions that are used more than once in this module
and/or abstractions to indicate the intended use of the data
- type:</p>
+ type. For more details on public key data types
+ see the <seealso marker="public_key:public_key_records"> public_key user's guide.</seealso>
+ </p>
<p> boolean() = true | false</p>
<p> string() = [byte()]</p>
- <p> public_key() = #'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</p>
- <p> private_key() = #'RSAPublicKey'{}| {integer(), #'Dss-Parms'{}}| term()</p>
- <p> public_key_algorithm() = 'ssh-rsa'| 'ssh-dss' | atom()</p>
+ <p> public_key() = #'RSAPublicKey'{} | {integer(), #'Dss-Parms'{}} | term()</p>
+ <p> private_key() = #'RSAPrivateKey'{} | #'DSAPrivateKey'{} | term()</p>
+ <p> public_key_algorithm() = 'ssh-rsa' | 'ssh-dss' | atom()</p>
</section>
<funcs>
@@ -56,7 +58,7 @@
<fsummary>Fetches the hosts private key </fsummary>
<type>
<v>Algorithm = public_key_algorithm()</v>
- <d> Host key algorithm. Should support 'ssh-rsa'| 'ssh-dss' but additional algorithms
+ <d> Host key algorithm. Should support 'ssh-rsa' | 'ssh-dss' but additional algorithms
can be handled.</d>
<v> DaemonOptions = proplists:proplist() </v>
<d>Options provided to <seealso marker="ssh#daemon-2">ssh:daemon/[2,3]</seealso></d>
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 93d0b54f57..2ef2859fd7 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -53,7 +53,6 @@ MODULES= \
ssh_connection_sup \
ssh_connection \
ssh_connection_handler \
- ssh_connection_manager \
ssh_shell \
ssh_system_sup \
ssh_subsystem_sup \
@@ -67,12 +66,12 @@ MODULES= \
ssh_file \
ssh_io \
ssh_math \
+ ssh_message \
ssh_no_io \
ssh_sftp \
ssh_sftpd \
ssh_sftpd_file\
ssh_transport \
- ssh_userreg \
ssh_xfer
PUBLIC_HRL_FILES= ssh.hrl ssh_userauth.hrl ssh_xfer.hrl
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 49707f3378..74d7293be0 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -8,6 +8,7 @@
ssh_acceptor,
ssh_acceptor_sup,
ssh_auth,
+ ssh_message,
ssh_bits,
ssh_cli,
ssh_client_key_api,
@@ -15,7 +16,6 @@
ssh_channel_sup,
ssh_connection,
ssh_connection_handler,
- ssh_connection_manager,
ssh_connection_sup,
ssh_daemon_channel,
ssh_shell,
@@ -34,7 +34,6 @@
ssh_sup,
ssh_system_sup,
ssh_transport,
- ssh_userreg,
ssh_xfer]},
{registered, []},
{applications, [kernel, stdlib, crypto, public_key]},
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index 7d5478c3f6..2685b1553b 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -32,9 +32,8 @@
shell/1, shell/2, shell/3]).
%%--------------------------------------------------------------------
-%% Function: start([, Type]) -> ok
-%%
-%% Type = permanent | transient | temporary
+-spec start() -> ok.
+-spec start(permanent | transient | temporary) -> ok.
%%
%% Description: Starts the ssh application. Default type
%% is temporary. see application(3)
@@ -52,7 +51,7 @@ start(Type) ->
application:start(ssh, Type).
%%--------------------------------------------------------------------
-%% Function: stop() -> ok
+-spec stop() -> ok.
%%
%% Description: Stops the ssh application.
%%--------------------------------------------------------------------
@@ -60,13 +59,8 @@ stop() ->
application:stop(ssh).
%%--------------------------------------------------------------------
-%% Function: connect(Host, Port, Options) ->
-%% connect(Host, Port, Options, Timeout -> ConnectionRef | {error, Reason}
-%%
-%% Host - string()
-%% Port - integer()
-%% Options - [{Option, Value}]
-%% Timeout - infinity | integer().
+-spec connect(string(), integer(), proplists:proplists()) -> {ok, pid()} | {error, term()}.
+-spec connect(string(), integer(), proplists:proplists(), timeout()) -> {ok, pid()} | {error, term()}.
%%
%% Description: Starts an ssh connection.
%%--------------------------------------------------------------------
@@ -77,83 +71,52 @@ connect(Host, Port, Options, Timeout) ->
{error, _Reason} = Error ->
Error;
{SocketOptions, SshOptions} ->
- DisableIpv6 = proplists:get_value(ipv6_disabled, SshOptions, false),
- Inet = inetopt(DisableIpv6),
- do_connect(Host, Port, [Inet | SocketOptions],
- [{user_pid, self()}, {host, Host} | fix_idle_time(SshOptions)], Timeout, DisableIpv6)
+ {_, Transport, _} = TransportOpts =
+ proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}),
+ Inet = proplists:get_value(inet, SshOptions, inet),
+ try Transport:connect(Host, Port, [ {active, false}, Inet | SocketOptions], Timeout) of
+ {ok, Socket} ->
+ Opts = [{user_pid, self()}, {host, Host} | fix_idle_time(SshOptions)],
+ ssh_connection_handler:start_connection(client, Socket, Opts, Timeout);
+ {error, Reason} ->
+ {error, Reason}
+ catch
+ exit:{function_clause, _} ->
+ {error, {options, {transport, TransportOpts}}};
+ exit:badarg ->
+ {error, {options, {socket_options, SocketOptions}}}
+ end
end.
-do_connect(Host, Port, SocketOptions, SshOptions, Timeout, DisableIpv6) ->
- try sshc_sup:start_child([[{address, Host}, {port, Port},
- {role, client},
- {channel_pid, self()},
- {socket_opts, SocketOptions},
- {ssh_opts, SshOptions}]]) of
- {ok, ConnectionSup} ->
- {ok, Manager} =
- ssh_connection_sup:connection_manager(ConnectionSup),
- msg_loop(Manager, DisableIpv6, Host, Port, SocketOptions, SshOptions, Timeout)
- catch
- exit:{noproc, _} ->
- {error, ssh_not_started}
- end.
-msg_loop(Manager, DisableIpv6, Host, Port, SocketOptions, SshOptions, Timeout) ->
- receive
- {Manager, is_connected} ->
- {ok, Manager};
- %% When the connection fails
- %% ssh_connection_sup:connection_manager
- %% might return undefined as the connection manager
- %% could allready have terminated, so we will not
- %% match the Manager in this case
- {_, not_connected, {error, econnrefused}} when DisableIpv6 == false ->
- do_connect(Host, Port, proplists:delete(inet6, SocketOptions),
- SshOptions, Timeout, true);
- {_, not_connected, {error, Reason}} ->
- {error, Reason};
- {_, not_connected, Other} ->
- {error, Other};
- {From, user_password} ->
- Pass = io:get_password(),
- From ! Pass,
- msg_loop(Manager, DisableIpv6, Host, Port, SocketOptions, SshOptions, Timeout);
- {From, question} ->
- Answer = io:get_line(""),
- From ! Answer,
- msg_loop(Manager, DisableIpv6, Host, Port, SocketOptions, SshOptions, Timeout)
- after Timeout ->
- ssh_connection_manager:stop(Manager),
- {error, timeout}
- end.
%%--------------------------------------------------------------------
-%% Function: close(ConnectionRef) -> ok
+-spec close(pid()) -> ok.
%%
%% Description: Closes an ssh connection.
%%--------------------------------------------------------------------
close(ConnectionRef) ->
- ssh_connection_manager:stop(ConnectionRef).
+ ssh_connection_handler:stop(ConnectionRef).
%%--------------------------------------------------------------------
-%% Function: connection_info(ConnectionRef) -> [{Option, Value}]
+-spec connection_info(pid(), [atom()]) -> [{atom(), term()}].
%%
%% Description: Retrieves information about a connection.
%%--------------------------------------------------------------------
connection_info(ConnectionRef, Options) ->
- ssh_connection_manager:connection_info(ConnectionRef, Options).
+ ssh_connection_handler:connection_info(ConnectionRef, Options).
%%--------------------------------------------------------------------
-%% Function: channel_info(ConnectionRef) -> [{Option, Value}]
+-spec channel_info(pid(), channel_id(), [atom()]) -> [{atom(), term()}].
%%
%% Description: Retrieves information about a connection.
%%--------------------------------------------------------------------
channel_info(ConnectionRef, ChannelId, Options) ->
- ssh_connection_manager:channel_info(ConnectionRef, ChannelId, Options).
+ ssh_connection_handler:channel_info(ConnectionRef, ChannelId, Options).
%%--------------------------------------------------------------------
-%% Function: daemon(Port) ->
-%% daemon(Port, Options) ->
-%% daemon(Address, Port, Options) -> SshSystemRef
-%%
+-spec daemon(integer()) -> {ok, pid()}.
+-spec daemon(integer(), proplists:proplist()) -> {ok, pid()}.
+-spec daemon(any | inet:ip_address(), integer(), proplists:proplist()) -> {ok, pid()}.
+
%% Description: Starts a server listening for SSH connections
%% on the given port.
%%--------------------------------------------------------------------
@@ -170,11 +133,11 @@ daemon(HostAddr, Port, Options0) ->
_ ->
Options0
end,
- DisableIpv6 = proplists:get_value(ipv6_disabled, Options0, false),
+
{Host, Inet, Options} = case HostAddr of
any ->
{ok, Host0} = inet:gethostname(),
- {Host0, inetopt(DisableIpv6), Options1};
+ {Host0, proplists:get_value(inet, Options1, inet), Options1};
{_,_,_,_} ->
{HostAddr, inet,
[{ip, HostAddr} | Options1]};
@@ -185,9 +148,8 @@ daemon(HostAddr, Port, Options0) ->
start_daemon(Host, Port, Options, Inet).
%%--------------------------------------------------------------------
-%% Function: stop_listener(SysRef) -> ok
-%% stop_listener(Address, Port) -> ok
-%%
+-spec stop_listener(pid()) -> ok.
+-spec stop_listener(inet:ip_address(), integer()) -> ok.
%%
%% Description: Stops the listener, but leaves
%% existing connections started by the listener up and running.
@@ -198,9 +160,8 @@ stop_listener(Address, Port) ->
ssh_system_sup:stop_listener(Address, Port).
%%--------------------------------------------------------------------
-%% Function: stop_daemon(SysRef) -> ok
-%%% stop_daemon(Address, Port) -> ok
-%%
+-spec stop_daemon(pid()) -> ok.
+-spec stop_daemon(inet:ip_address(), integer()) -> ok.
%%
%% Description: Stops the listener and all connections started by
%% the listener.
@@ -211,9 +172,10 @@ stop_daemon(Address, Port) ->
ssh_system_sup:stop_system(Address, Port).
%%--------------------------------------------------------------------
-%% Function: shell(Host [,Port,Options]) -> {ok, ConnectionRef} |
-%% {error, Reason}
-%%
+-spec shell(string()) -> _.
+-spec shell(string(), proplists:proplist()) -> _.
+-spec shell(string(), integer(), proplists:proplist()) -> _.
+
%% Host = string()
%% Port = integer()
%% Options = [{Option, Value}]
@@ -379,9 +341,9 @@ handle_ssh_option({user_dir, Value} = Opt) when is_list(Value) ->
Opt;
handle_ssh_option({user_dir_fun, Value} = Opt) when is_function(Value) ->
Opt;
-handle_ssh_option({silently_accept_hosts, Value} = Opt) when Value == true; Value == false ->
+handle_ssh_option({silently_accept_hosts, Value} = Opt) when is_boolean(Value) ->
Opt;
-handle_ssh_option({user_interaction, Value} = Opt) when Value == true; Value == false ->
+handle_ssh_option({user_interaction, Value} = Opt) when is_boolean(Value) ->
Opt;
handle_ssh_option({public_key_alg, ssh_dsa}) ->
{public_key_alg, 'ssh-dss'};
@@ -429,9 +391,8 @@ handle_ssh_option({disconnectfun , Value} = Opt) when is_function(Value) ->
handle_ssh_option({failfun, Value} = Opt) when is_function(Value) ->
Opt;
-handle_ssh_option({ipv6_disabled, Value} = Opt) when Value == true;
- Value == false ->
- Opt;
+handle_ssh_option({ipv6_disabled, Value} = Opt) when is_boolean(Value) ->
+ throw({error, {{ipv6_disabled, Opt}, option_no_longer_valid_use_inet_option_instead}});
handle_ssh_option({transport, {Protocol, Cb, ClosTag}} = Opt) when is_atom(Protocol),
is_atom(Cb),
is_atom(ClosTag) ->
@@ -440,13 +401,14 @@ handle_ssh_option({subsystems, Value} = Opt) when is_list(Value) ->
Opt;
handle_ssh_option({ssh_cli, {Cb, _}}= Opt) when is_atom(Cb) ->
Opt;
+handle_ssh_option({ssh_cli, no_cli} = Opt) ->
+ Opt;
handle_ssh_option({shell, {Module, Function, _}} = Opt) when is_atom(Module),
is_atom(Function) ->
Opt;
handle_ssh_option({shell, Value} = Opt) when is_function(Value) ->
Opt;
-handle_ssh_option({quiet_mode, Value} = Opt) when Value == true;
- Value == false ->
+handle_ssh_option({quiet_mode, Value} = Opt) when is_boolean(Value) ->
Opt;
handle_ssh_option({idle_time, Value} = Opt) when is_integer(Value), Value > 0 ->
Opt;
@@ -459,10 +421,8 @@ handle_inet_option({active, _} = Opt) ->
throw({error, {{eoptions, Opt}, "Ssh has built in flow control, "
"and activ is handled internaly user is not allowd"
"to specify this option"}});
-handle_inet_option({inet, _} = Opt) ->
- throw({error, {{eoptions, Opt},"Is set internaly use ipv6_disabled to"
- " enforce iv4 in the server, client will fallback to ipv4 if"
- " it can not use ipv6"}});
+handle_inet_option({inet, Value} = Opt) when (Value == inet) or (Value == inet6) ->
+ Opt;
handle_inet_option({reuseaddr, _} = Opt) ->
throw({error, {{eoptions, Opt},"Is set internaly user is not allowd"
"to specify this option"}});
@@ -485,18 +445,3 @@ handle_pref_algs([H|T], Acc) ->
_ ->
false
end.
-%% Has IPv6 been disabled?
-inetopt(true) ->
- inet;
-inetopt(false) ->
- case gen_tcp:listen(0, [inet6]) of
- {ok, Dummyport} ->
- gen_tcp:close(Dummyport),
- inet6;
- _ ->
- inet
- end.
-
-%%%
-%% Deprecated
-%%%
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 4fd347ba8f..94ced9da6f 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -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
@@ -29,6 +29,8 @@
-define(SSH_DEFAULT_PORT, 22).
-define(SSH_MAX_PACKET_SIZE, (256*1024)).
-define(SSH_LENGHT_INDICATOR_SIZE, 4).
+-define(REKEY_TIMOUT, 3600000).
+-define(REKEY_DATA_TIMOUT, 60000).
-define(FALSE, 0).
-define(TRUE, 1).
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index d023656c32..91905b2eaf 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -25,7 +25,6 @@
-export([start_link/5]).
%% spawn export
-%% TODO: system messages
-export([acceptor_init/6, acceptor_loop/6]).
-define(SLEEP_TIME, 200).
@@ -81,17 +80,15 @@ acceptor_loop(Callback, Port, Address, Opts, ListenSocket, AcceptTimeout) ->
ListenSocket, AcceptTimeout)
end.
-handle_connection(Callback, Address, Port, Options, Socket) ->
+handle_connection(_Callback, Address, Port, Options, Socket) ->
SystemSup = ssh_system_sup:system_supervisor(Address, Port),
{ok, SubSysSup} = ssh_system_sup:start_subsystem(SystemSup, Options),
- ConnectionSup = ssh_system_sup:connection_supervisor(SystemSup),
- {ok, Pid} =
- ssh_connection_sup:start_manager_child(ConnectionSup,
- [server, Socket, Options]),
- Callback:controlling_process(Socket, Pid),
- SshOpts = proplists:get_value(ssh_opts, Options),
- Pid ! {start_connection, server, [Address, Port, Socket, SshOpts, SubSysSup]}.
-
+ ConnectionSup = ssh_subsystem_sup:connection_supervisor(SubSysSup),
+ ssh_connection_handler:start_connection(server, Socket,
+ [{supervisors, [{system_sup, SystemSup},
+ {subsystem_sup, SubSysSup},
+ {connection_sup, ConnectionSup}]}
+ | Options], infinity).
handle_error(timeout) ->
ok;
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index cb0c7751f0..1fa3df847f 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -30,8 +30,7 @@
-export([publickey_msg/1, password_msg/1, keyboard_interactive_msg/1,
service_request_msg/1, init_userauth_request_msg/1,
userauth_request_msg/1, handle_userauth_request/3,
- handle_userauth_info_request/3, handle_userauth_info_response/2,
- userauth_messages/0
+ handle_userauth_info_request/3, handle_userauth_info_response/2
]).
%%--------------------------------------------------------------------
@@ -43,7 +42,6 @@ publickey_msg([Alg, #ssh{user = User,
opts = Opts} = Ssh]) ->
Hash = sha, %% Maybe option?!
- ssh_bits:install_messages(userauth_pk_messages()),
KeyCb = proplists:get_value(key_cb, Opts, ssh_file),
case KeyCb:user_key(Alg, Opts) of
@@ -69,7 +67,6 @@ publickey_msg([Alg, #ssh{user = User,
password_msg([#ssh{opts = Opts, io_cb = IoCb,
user = User, service = Service} = Ssh]) ->
- ssh_bits:install_messages(userauth_passwd_messages()),
Password = case proplists:get_value(password, Opts) of
undefined ->
user_interaction(IoCb, Ssh);
@@ -99,7 +96,6 @@ user_interaction(IoCb, Ssh) ->
%% See RFC 4256 for info on keyboard-interactive
keyboard_interactive_msg([#ssh{user = User,
service = Service} = Ssh]) ->
- ssh_bits:install_messages(userauth_keyboard_interactive_messages()),
ssh_transport:ssh_packet(
#ssh_msg_userauth_request{user = User,
service = Service,
@@ -239,7 +235,6 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
partial_success = false}, Ssh)}
end;
?FALSE ->
- ssh_bits:install_messages(userauth_pk_messages()),
{not_authorized, {User, undefined},
ssh_transport:ssh_packet(
#ssh_msg_userauth_pk_ok{algorithm_name = Alg,
@@ -275,26 +270,10 @@ handle_userauth_info_request(
handle_userauth_info_response(#ssh_msg_userauth_info_response{},
_Auth) ->
throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = "Server does not support"
- "keyboard-interactive",
+ description = "Server does not support"
+ "keyboard-interactive",
language = "en"}).
-userauth_messages() ->
- [ {ssh_msg_userauth_request, ?SSH_MSG_USERAUTH_REQUEST,
- [string,
- string,
- string,
- '...']},
-
- {ssh_msg_userauth_failure, ?SSH_MSG_USERAUTH_FAILURE,
- [string,
- boolean]},
-
- {ssh_msg_userauth_success, ?SSH_MSG_USERAUTH_SUCCESS,
- []},
-
- {ssh_msg_userauth_banner, ?SSH_MSG_USERAUTH_BANNER,
- [string,
- string]}].
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -386,13 +365,8 @@ algorithm_string('ssh-rsa') ->
algorithm_string('ssh-dss') ->
"ssh-dss".
-decode_keyboard_interactive_prompts(NumPrompts, Data) ->
- Types = lists:append(lists:duplicate(NumPrompts, [string, boolean])),
- pairwise_tuplify(ssh_bits:decode(Data, Types)).
-
-pairwise_tuplify([E1, E2 | Rest]) -> [{E1, E2} | pairwise_tuplify(Rest)];
-pairwise_tuplify([]) -> [].
-
+decode_keyboard_interactive_prompts(_NumPrompts, Data) ->
+ ssh_message:decode_keyboard_interactive_prompts(Data, []).
keyboard_interact_get_responses(IoCb, Opts, Name, Instr, PromptInfos) ->
NumPrompts = length(PromptInfos),
@@ -431,50 +405,29 @@ keyboard_interact(IoCb, Name, Instr, Prompts, Opts) ->
end,
Prompts).
-userauth_passwd_messages() ->
- [
- {ssh_msg_userauth_passwd_changereq, ?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ,
- [string,
- string]}
- ].
-
-userauth_keyboard_interactive_messages() ->
- [ {ssh_msg_userauth_info_request, ?SSH_MSG_USERAUTH_INFO_REQUEST,
- [string,
- string,
- string,
- uint32,
- '...']},
-
- {ssh_msg_userauth_info_response, ?SSH_MSG_USERAUTH_INFO_RESPONSE,
- [uint32,
- '...']}
- ].
-
-userauth_pk_messages() ->
- [ {ssh_msg_userauth_pk_ok, ?SSH_MSG_USERAUTH_PK_OK,
- [string, % algorithm name
- binary]} % key blob
- ].
-
other_alg('ssh-rsa') ->
'ssh-dss';
other_alg('ssh-dss') ->
'ssh-rsa'.
-decode_public_key_v2(K_S, "ssh-rsa") ->
- case ssh_bits:decode(K_S,[string,mpint,mpint]) of
- ["ssh-rsa", E, N] ->
- {ok, #'RSAPublicKey'{publicExponent = E, modulus = N}};
- _ ->
- {error, bad_format}
- end;
-decode_public_key_v2(K_S, "ssh-dss") ->
- case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of
- ["ssh-dss",P,Q,G,Y] ->
- {ok, {Y, #'Dss-Parms'{p = P, q = Q, g = G}}};
- _ ->
- {error, bad_format}
- end;
+decode_public_key_v2(<<?UINT32(Len0), _:Len0/binary,
+ ?UINT32(Len1), BinE:Len1/binary,
+ ?UINT32(Len2), BinN:Len2/binary>>
+ ,"ssh-rsa") ->
+ E = ssh_bits:erlint(Len1, BinE),
+ N = ssh_bits:erlint(Len2, BinN),
+ {ok, #'RSAPublicKey'{publicExponent = E, modulus = N}};
+decode_public_key_v2(<<?UINT32(Len0), _:Len0/binary,
+ ?UINT32(Len1), BinP:Len1/binary,
+ ?UINT32(Len2), BinQ:Len2/binary,
+ ?UINT32(Len3), BinG:Len3/binary,
+ ?UINT32(Len4), BinY:Len4/binary>>
+ , "ssh-dss") ->
+ P = ssh_bits:erlint(Len1, BinP),
+ Q = ssh_bits:erlint(Len2, BinQ),
+ G = ssh_bits:erlint(Len3, BinG),
+ Y = ssh_bits:erlint(Len4, BinY),
+ {ok, {Y, #'Dss-Parms'{p = P, q = Q, g = G}}};
+
decode_public_key_v2(_, _) ->
{error, bad_format}.
diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl
index fc6efc817f..2b0241cb83 100644
--- a/lib/ssh/src/ssh_bits.erl
+++ b/lib/ssh/src/ssh_bits.erl
@@ -25,19 +25,9 @@
-include("ssh.hrl").
--export([encode/1, encode/2]).
--export([decode/1, decode/2, decode/3]).
--export([mpint/1, bignum/1, string/1, name_list/1]).
--export([b64_encode/1, b64_decode/1]).
--export([install_messages/1, uninstall_messages/1]).
-
-%% integer utils
--export([isize/1]).
+-export([encode/2]).
+-export([mpint/1, erlint/2, string/1, name_list/1]).
-export([random/1]).
--export([xor_bits/2, fill_bits/2]).
--export([i2bin/2, bin2i/1]).
-
--import(lists, [foreach/2, reverse/1]).
-define(name_list(X),
(fun(B) -> ?binary(B) end)(list_to_binary(name_concat(X)))).
@@ -95,38 +85,6 @@ mpint_pos(X,I,Ds) ->
mpint_pos(X bsr 8,I+1,[(X band 255)|Ds]).
-%% BIGNUM representation SSH1
-bignum(X) ->
- XSz = isize(X),
- Pad = (8 - (XSz rem 8)) rem 8,
- <<?UINT16(XSz),0:Pad/unsigned-integer,X:XSz/big-unsigned-integer>>.
-
-
-install_messages(Codes) ->
- foreach(fun({Name, Code, Ts}) ->
- put({msg_name,Code}, {Name,Ts}),
- put({msg_code,Name}, {Code,Ts})
- end, Codes).
-
-uninstall_messages(Codes) ->
- foreach(fun({Name, Code, _Ts}) ->
- erase({msg_name,Code}),
- erase({msg_code,Name})
- end, Codes).
-
-%%
-%% Encode a record, the type spec is expected to be
-%% in process dictionary under the key {msg_code, RecodeName}
-%%
-encode(Record) ->
- case get({msg_code, element(1, Record)}) of
- undefined ->
- {error, unimplemented};
- {Code, Ts} ->
- Data = enc(tl(tuple_to_list(Record)), Ts),
- list_to_binary([Code, Data])
- end.
-
encode(List, Types) ->
list_to_binary(enc(List, Types)).
@@ -136,230 +94,58 @@ encode(List, Types) ->
enc(Xs, Ts) ->
enc(Xs, Ts, 0).
-enc(Xs, [Type|Ts], Offset) ->
- case Type of
- boolean ->
- X=hd(Xs),
- [?boolean(X) | enc(tl(Xs), Ts, Offset+1)];
- byte ->
- X=hd(Xs),
- [?byte(X) | enc(tl(Xs), Ts,Offset+1)];
- uint16 ->
- X=hd(Xs),
- [?uint16(X) | enc(tl(Xs), Ts,Offset+2)];
- uint32 ->
- X=hd(Xs),
- [?uint32(X) | enc(tl(Xs), Ts,Offset+4)];
- uint64 ->
- X=hd(Xs),
- [?uint64(X) | enc(tl(Xs), Ts,Offset+8)];
- mpint ->
- Y=mpint(hd(Xs)),
- [Y | enc(tl(Xs), Ts,Offset+size(Y))];
- bignum ->
- Y=bignum(hd(Xs)),
- [Y | enc(tl(Xs),Ts,Offset+size(Y))];
- string ->
- X0=hd(Xs),
- Y=?string(X0),
- [Y | enc(tl(Xs),Ts,Offset+size(Y))];
- binary ->
- X0=hd(Xs),
- Y=?binary(X0),
- [Y | enc(tl(Xs), Ts,Offset+size(Y))];
- name_list ->
- X0=hd(Xs),
- Y=?name_list(X0),
- [Y | enc(tl(Xs), Ts, Offset+size(Y))];
- cookie ->
- [random(16) | enc(tl(Xs), Ts, Offset+16)];
- {pad,N} ->
- K = (N - (Offset rem N)) rem N,
- [fill_bits(K,0) | enc(Xs, Ts, Offset+K)];
- '...' when Ts==[] ->
- X=hd(Xs),
- if is_binary(X) ->
- [X];
- is_list(X) ->
- [list_to_binary(X)];
- X==undefined ->
- []
- end
+enc(Xs, [boolean|Ts], Offset) ->
+ X = hd(Xs),
+ [?boolean(X) | enc(tl(Xs), Ts, Offset+1)];
+enc(Xs, [byte|Ts], Offset) ->
+ X = hd(Xs),
+ [?byte(X) | enc(tl(Xs), Ts,Offset+1)];
+enc(Xs, [uint16|Ts], Offset) ->
+ X = hd(Xs),
+ [?uint16(X) | enc(tl(Xs), Ts,Offset+2)];
+enc(Xs, [uint32 |Ts], Offset) ->
+ X = hd(Xs),
+ [?uint32(X) | enc(tl(Xs), Ts,Offset+4)];
+enc(Xs, [uint64|Ts], Offset) ->
+ X = hd(Xs),
+ [?uint64(X) | enc(tl(Xs), Ts,Offset+8)];
+enc(Xs, [mpint|Ts], Offset) ->
+ Y = mpint(hd(Xs)),
+ [Y | enc(tl(Xs), Ts,Offset+size(Y))];
+enc(Xs, [string|Ts], Offset) ->
+ X0 = hd(Xs),
+ Y = ?string(X0),
+ [Y | enc(tl(Xs),Ts,Offset+size(Y))];
+enc(Xs, [binary|Ts], Offset) ->
+ X0 = hd(Xs),
+ Y = ?binary(X0),
+ [Y | enc(tl(Xs), Ts,Offset+size(Y))];
+enc(Xs, [name_list|Ts], Offset) ->
+ X0 = hd(Xs),
+ Y = ?name_list(X0),
+ [Y | enc(tl(Xs), Ts, Offset+size(Y))];
+enc(Xs, [cookie|Ts], Offset) ->
+ [random(16) | enc(tl(Xs), Ts, Offset+16)];
+enc(Xs, [{pad,N}|Ts], Offset) ->
+ K = (N - (Offset rem N)) rem N,
+ [fill_bits(K,0) | enc(Xs, Ts, Offset+K)];
+enc(Xs, ['...'| []], _Offset) ->
+ X = hd(Xs),
+ if is_binary(X) ->
+ [X];
+ is_list(X) ->
+ [list_to_binary(X)];
+ X==undefined ->
+ []
end;
enc([], [],_) ->
[].
-
-
-%%
-%% Decode a SSH record the type is encoded as the first byte
-%% and the type spec MUST be installed in {msg_name, ID}
-%%
-
-decode(Binary = <<?BYTE(ID), _/binary>>) ->
- case get({msg_name, ID}) of
- undefined ->
- {unknown, Binary};
- {Name, Ts} ->
- {_, Elems} = decode(Binary,1,Ts),
- list_to_tuple([Name | Elems])
- end.
-
-%%
-%% Decode a binary form offset 0
-%%
-
-decode(Binary, Types) when is_binary(Binary) andalso is_list(Types) ->
- {_,Elems} = decode(Binary, 0, Types),
- Elems.
-
-
-%%
-%% Decode a binary from byte offset Offset
-%% return {UpdatedOffset, DecodedElements}
-%%
-decode(Binary, Offset, Types) ->
- decode(Binary, Offset, Types, []).
-
-decode(Binary, Offset, [Type|Ts], Acc) ->
- case Type of
- boolean ->
- <<_:Offset/binary, ?BOOLEAN(X0), _/binary>> = Binary,
- X = if X0 == 0 -> false; true -> true end,
- decode(Binary, Offset+1, Ts, [X | Acc]);
-
- byte ->
- <<_:Offset/binary, ?BYTE(X), _/binary>> = Binary,
- decode(Binary, Offset+1, Ts, [X | Acc]);
-
- uint16 ->
- <<_:Offset/binary, ?UINT16(X), _/binary>> = Binary,
- decode(Binary, Offset+2, Ts, [X | Acc]);
-
- uint32 ->
- <<_:Offset/binary, ?UINT32(X), _/binary>> = Binary,
- decode(Binary, Offset+4, Ts, [X | Acc]);
-
- uint64 ->
- <<_:Offset/binary, ?UINT64(X), _/binary>> = Binary,
- decode(Binary, Offset+8, Ts, [X | Acc]);
-
- mpint ->
- <<_:Offset/binary, ?UINT32(L), X0:L/binary,_/binary>> = Binary,
- Sz = L*8,
- <<X:Sz/big-signed-integer>> = X0,
- decode(Binary, Offset+4+L, Ts, [X | Acc]);
-
- bignum ->
- <<_:Offset/binary, ?UINT16(Bits),_/binary>> = Binary,
- L = (Bits+7) div 8,
- Pad = (8 - (Bits rem 8)) rem 8,
- <<_:Offset/binary, _:16, _:Pad, X:Bits/big-unsigned-integer,
- _/binary>> = Binary,
- decode(Binary, Offset+2+L, Ts, [X | Acc]);
-
- string ->
- Size = size(Binary),
- if Size < Offset + 4 ->
- %% empty string at end
- {Size, reverse(["" | Acc])};
- true ->
- <<_:Offset/binary,?UINT32(L), X:L/binary,_/binary>> =
- Binary,
- decode(Binary, Offset+4+L, Ts, [binary_to_list(X) |
- Acc])
- end;
-
- binary ->
- <<_:Offset/binary,?UINT32(L), X:L/binary,_/binary>> = Binary,
- decode(Binary, Offset+4+L, Ts, [X | Acc]);
-
- name_list ->
- <<_:Offset/binary,?UINT32(L), X:L/binary,_/binary>> = Binary,
- List = string:tokens(binary_to_list(X), ","),
- decode(Binary, Offset+4+L, Ts, [List | Acc]);
-
- cookie ->
- <<_:Offset/binary, X:16/binary, _/binary>> = Binary,
- decode(Binary, Offset+16, Ts, [X | Acc]);
-
- {pad,N} -> %% pad offset to a multiple of N
- K = (N - (Offset rem N)) rem N,
- decode(Binary, Offset+K, Ts, Acc);
-
+erlint(Len, BinInt) ->
+ Sz = Len*8,
+ <<Int:Sz/big-signed-integer>> = BinInt,
+ Int.
- '...' when Ts==[] ->
- <<_:Offset/binary, X/binary>> = Binary,
- {Offset+size(X), reverse([X | Acc])}
- end;
-decode(_Binary, Offset, [], Acc) ->
- {Offset, reverse(Acc)}.
-
-
-
-%% HACK WARNING :-)
--define(VERSION_MAGIC, 131).
--define(SMALL_INTEGER_EXT, $a).
--define(INTEGER_EXT, $b).
--define(SMALL_BIG_EXT, $n).
--define(LARGE_BIG_EXT, $o).
-
-isize(N) when N > 0 ->
- case term_to_binary(N) of
- <<?VERSION_MAGIC, ?SMALL_INTEGER_EXT, X>> ->
- isize_byte(X);
- <<?VERSION_MAGIC, ?INTEGER_EXT, X3,X2,X1,X0>> ->
- isize_bytes([X3,X2,X1,X0]);
- <<?VERSION_MAGIC, ?SMALL_BIG_EXT, S:8/big-unsigned-integer, 0,
- Ds:S/binary>> ->
- K = S - 1,
- <<_:K/binary, Top>> = Ds,
- isize_byte(Top)+K*8;
- <<?VERSION_MAGIC, ?LARGE_BIG_EXT, S:32/big-unsigned-integer, 0,
- Ds:S/binary>> ->
- K = S - 1,
- <<_:K/binary, Top>> = Ds,
- isize_byte(Top)+K*8
- end;
-isize(0) -> 0.
-
-%% big endian byte list
-isize_bytes([0|L]) ->
- isize_bytes(L);
-isize_bytes([Top|L]) ->
- isize_byte(Top) + length(L)*8.
-
-%% Well could be improved
-isize_byte(X) ->
- if X >= 2#10000000 -> 8;
- X >= 2#1000000 -> 7;
- X >= 2#100000 -> 6;
- X >= 2#10000 -> 5;
- X >= 2#1000 -> 4;
- X >= 2#100 -> 3;
- X >= 2#10 -> 2;
- X >= 2#1 -> 1;
- true -> 0
- end.
-
-%% Convert integer into binary
-%% When XLen is the wanted size in octets of the output
-i2bin(X, XLen) ->
- XSz = isize(X),
- Sz = XLen*8,
- if Sz < XSz ->
- exit(integer_to_large);
- true ->
- (<<X:Sz/big-unsigned-integer>>)
- end.
-
-%% Convert a binary into an integer
-%%
-bin2i(X) ->
- Sz = size(X)*8,
- <<Y:Sz/big-unsigned-integer>> = X,
- Y.
-
%%
%% Create a binary with constant bytes
%%
@@ -377,15 +163,6 @@ fill(N,C) ->
[C,Cs,Cs]
end.
-%% xor 2 binaries
-xor_bits(XBits, YBits) ->
- XSz = size(XBits)*8,
- YSz = size(YBits)*8,
- Sz = if XSz < YSz -> XSz; true -> YSz end, %% min
- <<X:Sz, _/binary>> = XBits,
- <<Y:Sz, _/binary>> = YBits,
- <<(X bxor Y):Sz>>.
-
%% random/1
%% Generate N random bytes
@@ -393,18 +170,5 @@ xor_bits(XBits, YBits) ->
random(N) ->
crypto:strong_rand_bytes(N).
-%%
-%% Base 64 encode/decode
-%%
-
-b64_encode(Bs) when is_list(Bs) ->
- base64:encode(Bs);
-b64_encode(Bin) when is_binary(Bin) ->
- base64:encode(Bin).
-
-b64_decode(Bin) when is_binary(Bin) ->
- base64:mime_decode(Bin);
-b64_decode(Cs) when is_list(Cs) ->
- base64:mime_decode(Cs).
diff --git a/lib/ssh/src/ssh_channel.erl b/lib/ssh/src/ssh_channel.erl
index 062ed764ca..508ae637cf 100644
--- a/lib/ssh/src/ssh_channel.erl
+++ b/lib/ssh/src/ssh_channel.erl
@@ -284,7 +284,7 @@ handle_info(Msg, #state{cm = ConnectionManager, channel_cb = Module,
terminate(Reason, #state{cm = ConnectionManager,
channel_id = ChannelId,
close_sent = false} = State) ->
- ssh_connection:close(ConnectionManager, ChannelId),
+ catch ssh_connection:close(ConnectionManager, ChannelId),
terminate(Reason, State#state{close_sent = true});
terminate(_, #state{channel_cb = Cb, channel_state = ChannelState}) ->
catch Cb:terminate(Cb, ChannelState),
diff --git a/lib/ssh/src/ssh_channel_sup.erl b/lib/ssh/src/ssh_channel_sup.erl
index 0093bce9c2..ee37ed35f8 100644
--- a/lib/ssh/src/ssh_channel_sup.erl
+++ b/lib/ssh/src/ssh_channel_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -31,7 +31,7 @@
-export([init/1]).
%%%=========================================================================
-%%% API
+%%% Internal API
%%%=========================================================================
start_link(Args) ->
supervisor:start_link(?MODULE, [Args]).
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 54911e757c..5cb1e133d3 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -32,9 +32,6 @@
%% ssh_channel callbacks
-export([init/1, handle_ssh_msg/2, handle_msg/2, terminate/2]).
-%% backwards compatibility
--export([listen/1, listen/2, listen/3, listen/4, stop/1]).
-
%% state
-record(state, {
cm,
@@ -65,14 +62,14 @@ init([Shell]) ->
%%
%% Description: Handles channel messages received on the ssh-connection.
%%--------------------------------------------------------------------
-handle_ssh_msg({ssh_cm, _ConnectionManager,
+handle_ssh_msg({ssh_cm, _ConnectionHandler,
{data, _ChannelId, _Type, Data}},
#state{group = Group} = State) ->
List = binary_to_list(Data),
to_group(List, Group),
{ok, State};
-handle_ssh_msg({ssh_cm, ConnectionManager,
+handle_ssh_msg({ssh_cm, ConnectionHandler,
{pty, ChannelId, WantReply,
{TermName, Width, Height, PixWidth, PixHeight, Modes}}},
State0) ->
@@ -85,53 +82,53 @@ handle_ssh_msg({ssh_cm, ConnectionManager,
modes = Modes},
buf = empty_buf()},
set_echo(State),
- ssh_connection:reply_request(ConnectionManager, WantReply,
+ ssh_connection:reply_request(ConnectionHandler, WantReply,
success, ChannelId),
{ok, State};
-handle_ssh_msg({ssh_cm, ConnectionManager,
+handle_ssh_msg({ssh_cm, ConnectionHandler,
{env, ChannelId, WantReply, _Var, _Value}}, State) ->
- ssh_connection:reply_request(ConnectionManager,
+ ssh_connection:reply_request(ConnectionHandler,
WantReply, failure, ChannelId),
{ok, State};
-handle_ssh_msg({ssh_cm, ConnectionManager,
+handle_ssh_msg({ssh_cm, ConnectionHandler,
{window_change, ChannelId, Width, Height, PixWidth, PixHeight}},
#state{buf = Buf, pty = Pty0} = State) ->
Pty = Pty0#ssh_pty{width = Width, height = Height,
pixel_width = PixWidth,
pixel_height = PixHeight},
{Chars, NewBuf} = io_request({window_change, Pty0}, Buf, Pty),
- write_chars(ConnectionManager, ChannelId, Chars),
+ write_chars(ConnectionHandler, ChannelId, Chars),
{ok, State#state{pty = Pty, buf = NewBuf}};
-handle_ssh_msg({ssh_cm, ConnectionManager,
+handle_ssh_msg({ssh_cm, ConnectionHandler,
{shell, ChannelId, WantReply}}, State) ->
- NewState = start_shell(ConnectionManager, State),
- ssh_connection:reply_request(ConnectionManager, WantReply,
+ NewState = start_shell(ConnectionHandler, State),
+ ssh_connection:reply_request(ConnectionHandler, WantReply,
success, ChannelId),
{ok, NewState#state{channel = ChannelId,
- cm = ConnectionManager}};
+ cm = ConnectionHandler}};
-handle_ssh_msg({ssh_cm, ConnectionManager,
+handle_ssh_msg({ssh_cm, ConnectionHandler,
{exec, ChannelId, WantReply, Cmd}}, #state{exec=undefined} = State) ->
{Reply, Status} = exec(Cmd),
- write_chars(ConnectionManager,
+ write_chars(ConnectionHandler,
ChannelId, io_lib:format("~p\n", [Reply])),
- ssh_connection:reply_request(ConnectionManager, WantReply,
+ ssh_connection:reply_request(ConnectionHandler, WantReply,
success, ChannelId),
- ssh_connection:exit_status(ConnectionManager, ChannelId, Status),
- ssh_connection:send_eof(ConnectionManager, ChannelId),
- {stop, ChannelId, State#state{channel = ChannelId, cm = ConnectionManager}};
-handle_ssh_msg({ssh_cm, ConnectionManager,
+ ssh_connection:exit_status(ConnectionHandler, ChannelId, Status),
+ ssh_connection:send_eof(ConnectionHandler, ChannelId),
+ {stop, ChannelId, State#state{channel = ChannelId, cm = ConnectionHandler}};
+handle_ssh_msg({ssh_cm, ConnectionHandler,
{exec, ChannelId, WantReply, Cmd}}, State) ->
- NewState = start_shell(ConnectionManager, Cmd, State),
- ssh_connection:reply_request(ConnectionManager, WantReply,
+ NewState = start_shell(ConnectionHandler, Cmd, State),
+ ssh_connection:reply_request(ConnectionHandler, WantReply,
success, ChannelId),
{ok, NewState#state{channel = ChannelId,
- cm = ConnectionManager}};
+ cm = ConnectionHandler}};
-handle_ssh_msg({ssh_cm, _ConnectionManager, {eof, _ChannelId}}, State) ->
+handle_ssh_msg({ssh_cm, _ConnectionHandler, {eof, _ChannelId}}, State) ->
{ok, State};
handle_ssh_msg({ssh_cm, _, {signal, _, _}}, State) ->
@@ -159,16 +156,16 @@ handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, Status}}, State) ->
%%
%% Description: Handles other channel messages.
%%--------------------------------------------------------------------
-handle_msg({ssh_channel_up, ChannelId, ConnectionManager},
+handle_msg({ssh_channel_up, ChannelId, ConnectionHandler},
#state{channel = ChannelId,
- cm = ConnectionManager} = State) ->
+ cm = ConnectionHandler} = State) ->
{ok, State};
handle_msg({Group, Req}, #state{group = Group, buf = Buf, pty = Pty,
- cm = ConnectionManager,
+ cm = ConnectionHandler,
channel = ChannelId} = State) ->
{Chars, NewBuf} = io_request(Req, Buf, Pty),
- write_chars(ConnectionManager, ChannelId, Chars),
+ write_chars(ConnectionHandler, ChannelId, Chars),
{ok, State#state{buf = NewBuf}};
handle_msg({'EXIT', Group, _Reason}, #state{group = Group,
@@ -399,12 +396,12 @@ move_cursor(From, To, #ssh_pty{width=Width, term=Type}) ->
%% %%% write out characters
%% %%% make sure that there is data to send
%% %%% before calling ssh_connection:send
-write_chars(ConnectionManager, ChannelId, Chars) ->
+write_chars(ConnectionHandler, ChannelId, Chars) ->
case erlang:iolist_size(Chars) of
0 ->
ok;
_ ->
- ssh_connection:send(ConnectionManager, ChannelId,
+ ssh_connection:send(ConnectionHandler, ChannelId,
?SSH_EXTENDED_DATA_DEFAULT, Chars)
end.
@@ -434,18 +431,20 @@ bin_to_list(L) when is_list(L) ->
bin_to_list(I) when is_integer(I) ->
I.
-start_shell(ConnectionManager, State) ->
+start_shell(ConnectionHandler, State) ->
Shell = State#state.shell,
+ ConnectionInfo = ssh_connection_handler:info(ConnectionHandler,
+ [peer, user]),
ShellFun = case is_function(Shell) of
true ->
{ok, User} =
- ssh_userreg:lookup_user(ConnectionManager),
+ proplists:get_value(user, ConnectionInfo),
case erlang:fun_info(Shell, arity) of
{arity, 1} ->
fun() -> Shell(User) end;
{arity, 2} ->
- {ok, PeerAddr} =
- ssh_connection_manager:peer_addr(ConnectionManager),
+ [{_, PeerAddr}] =
+ proplists:get_value(peer, ConnectionInfo),
fun() -> Shell(User, PeerAddr) end;
_ ->
Shell
@@ -457,12 +456,15 @@ start_shell(ConnectionManager, State) ->
Group = group:start(self(), ShellFun, [{echo, Echo}]),
State#state{group = Group, buf = empty_buf()}.
-start_shell(_ConnectionManager, Cmd, #state{exec={M, F, A}} = State) ->
+start_shell(_ConnectionHandler, Cmd, #state{exec={M, F, A}} = State) ->
Group = group:start(self(), {M, F, A++[Cmd]}, [{echo, false}]),
State#state{group = Group, buf = empty_buf()};
-start_shell(ConnectionManager, Cmd, #state{exec=Shell} = State) when is_function(Shell) ->
+start_shell(ConnectionHandler, Cmd, #state{exec=Shell} = State) when is_function(Shell) ->
+
+ ConnectionInfo = ssh_connection_handler:info(ConnectionHandler,
+ [peer, user]),
{ok, User} =
- ssh_userreg:lookup_user(ConnectionManager),
+ proplists:get_value(user, ConnectionInfo),
ShellFun =
case erlang:fun_info(Shell, arity) of
{arity, 1} ->
@@ -470,8 +472,8 @@ start_shell(ConnectionManager, Cmd, #state{exec=Shell} = State) when is_function
{arity, 2} ->
fun() -> Shell(Cmd, User) end;
{arity, 3} ->
- {ok, PeerAddr} =
- ssh_connection_manager:peer_addr(ConnectionManager),
+ [{_, PeerAddr}] =
+ proplists:get_value(peer, ConnectionInfo),
fun() -> Shell(Cmd, User, PeerAddr) end;
_ ->
Shell
@@ -505,31 +507,3 @@ not_zero(0, B) ->
not_zero(A, _) ->
A.
-%%% Backwards compatibility
-
-%%--------------------------------------------------------------------
-%% Function: listen(...) -> {ok,Pid} | ignore | {error,Error}
-%% Description: Starts a listening server
-%% Note that the pid returned is NOT the pid of this gen_server;
-%% this server is started when an SSH connection is made on the
-%% listening port
-%%--------------------------------------------------------------------
-listen(Shell) ->
- listen(Shell, 22).
-
-listen(Shell, Port) ->
- listen(Shell, Port, []).
-
-listen(Shell, Port, Opts) ->
- listen(Shell, any, Port, Opts).
-
-listen(Shell, HostAddr, Port, Opts) ->
- ssh:daemon(HostAddr, Port, [{shell, Shell} | Opts]).
-
-
-%%--------------------------------------------------------------------
-%% Function: stop(Pid) -> ok
-%% Description: Stops the listener
-%%--------------------------------------------------------------------
-stop(Pid) ->
- ssh:stop_listener(Pid).
diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl
index 932b0642f1..8421b07167 100644
--- a/lib/ssh/src/ssh_connect.hrl
+++ b/lib/ssh/src/ssh_connect.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -21,6 +21,8 @@
%%% Description : SSH connection protocol
+-type channel_id() :: integer().
+
-define(DEFAULT_PACKET_SIZE, 32768).
-define(DEFAULT_WINDOW_SIZE, 2*?DEFAULT_PACKET_SIZE).
-define(DEFAULT_TIMEOUT, 5000).
@@ -260,6 +262,7 @@
port,
options,
exec,
+ system_supervisor,
sub_system_supervisor,
connection_supervisor
}).
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index 9424cdd423..7016f349e8 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -29,232 +29,205 @@
-include("ssh_connect.hrl").
-include("ssh_transport.hrl").
+%% API
-export([session_channel/2, session_channel/4,
exec/4, shell/2, subsystem/4, send/3, send/4, send/5,
- send_eof/2, adjust_window/3, open_pty/3, open_pty/7,
- open_pty/9, setenv/5, window_change/4, window_change/6,
+ send_eof/2, adjust_window/3, setenv/5, close/2, reply_request/4]).
+
+%% Potential API currently unsupported and not tested
+-export([open_pty/3, open_pty/7,
+ open_pty/9, window_change/4, window_change/6,
direct_tcpip/6, direct_tcpip/8, tcpip_forward/3,
- cancel_tcpip_forward/3, signal/3, exit_status/3, encode_ip/1, close/2,
- reply_request/4]).
+ cancel_tcpip_forward/3, signal/3, exit_status/3]).
--export([channel_data/6, handle_msg/4, channel_eof_msg/1,
+%% Internal application API
+-export([channel_data/5, handle_msg/3, channel_eof_msg/1,
channel_close_msg/1, channel_success_msg/1, channel_failure_msg/1,
+ channel_status_msg/1,
channel_adjust_window_msg/2, channel_data_msg/3,
channel_open_msg/5, channel_open_confirmation_msg/4,
channel_open_failure_msg/4, channel_request_msg/4,
global_request_msg/3, request_failure_msg/0,
request_success_msg/1, bind/4, unbind/3, unbind_channel/2,
- bound_channel/3, messages/0]).
+ bound_channel/3, encode_ip/1]).
%%--------------------------------------------------------------------
-%%% Internal application API
+%%% API
%%--------------------------------------------------------------------
%%--------------------------------------------------------------------
-%% Function: session_channel(ConnectionManager
-%% [, InitialWindowSize, MaxPacketSize],
-%% Timeout) -> {ok, }
-%% ConnectionManager = pid()
-%% InitialWindowSize = integer()
-%% MaxPacketSize = integer()
-%%
+-spec session_channel(pid(), timeout()) -> {ok, channel_id()} | {error, term()}.
+-spec session_channel(pid(), integer(), integer(), timeout()) -> {ok, channel_id()} | {error, term()}.
+
%% Description: Opens a channel for a ssh session. A session is a
%% remote execution of a program. The program may be a shell, an
%% application, a system command, or some built-in subsystem.
%% --------------------------------------------------------------------
-session_channel(ConnectionManager, Timeout) ->
- session_channel(ConnectionManager,
+
+session_channel(ConnectionHandler, Timeout) ->
+ session_channel(ConnectionHandler,
?DEFAULT_WINDOW_SIZE, ?DEFAULT_PACKET_SIZE,
Timeout).
-session_channel(ConnectionManager, InitialWindowSize,
+
+session_channel(ConnectionHandler, InitialWindowSize,
MaxPacketSize, Timeout) ->
- ssh_connection_manager:open_channel(ConnectionManager, "session", <<>>,
+ case ssh_connection_handler:open_channel(ConnectionHandler, "session", <<>>,
InitialWindowSize,
- MaxPacketSize, Timeout).
+ MaxPacketSize, Timeout) of
+ {open, Channel} ->
+ {ok, Channel};
+ Error ->
+ Error
+ end.
+
%%--------------------------------------------------------------------
-%% Function: exec(ConnectionManager, ChannelId, Command, Timeout) ->
-%%
-%% ConnectionManager = pid()
-%% ChannelId = integer()
-%% Cmd = string()
-%% Timeout = integer()
-%%
+-spec exec(pid(), channel_id(), string(), timeout()) -> success | failure.
+
%% Description: Will request that the server start the
%% execution of the given command.
%%--------------------------------------------------------------------
-exec(ConnectionManager, ChannelId, Command, TimeOut) ->
- ssh_connection_manager:request(ConnectionManager, self(), ChannelId, "exec",
- true, [?string(Command)], TimeOut).
+exec(ConnectionHandler, ChannelId, Command, TimeOut) ->
+ ssh_connection_handler:request(ConnectionHandler, self(), ChannelId, "exec",
+ true, [?string(Command)], TimeOut).
+
%%--------------------------------------------------------------------
-%% Function: shell(ConnectionManager, ChannelId) ->
-%%
-%% ConnectionManager = pid()
-%% ChannelId = integer()
-%%
+-spec shell(pid(), channel_id()) -> _.
+
%% Description: Will request that the user's default shell (typically
%% defined in /etc/passwd in UNIX systems) be started at the other
%% end.
%%--------------------------------------------------------------------
-shell(ConnectionManager, ChannelId) ->
- ssh_connection_manager:request(ConnectionManager, self(), ChannelId,
+shell(ConnectionHandler, ChannelId) ->
+ ssh_connection_handler:request(ConnectionHandler, self(), ChannelId,
"shell", false, <<>>, 0).
%%--------------------------------------------------------------------
-%% Function: subsystem(ConnectionManager, ChannelId, SubSystem, TimeOut) ->
-%%
-%% ConnectionManager = pid()
-%% ChannelId = integer()
-%% SubSystem = string()
-%% TimeOut = integer()
-%%
+-spec subsystem(pid(), channel_id(), string(), timeout()) ->
+ success | failure | {error, timeout}.
%%
%% Description: Executes a predefined subsystem.
%%--------------------------------------------------------------------
-subsystem(ConnectionManager, ChannelId, SubSystem, TimeOut) ->
- ssh_connection_manager:request(ConnectionManager, self(),
+subsystem(ConnectionHandler, ChannelId, SubSystem, TimeOut) ->
+ ssh_connection_handler:request(ConnectionHandler, self(),
ChannelId, "subsystem",
true, [?string(SubSystem)], TimeOut).
%%--------------------------------------------------------------------
-%% Function: send(ConnectionManager, ChannelId, Type, Data, [TimeOut]) ->
+-spec send(pid(), channel_id(), iodata()) ->
+ ok | {error, closed}.
+-spec send(pid(), channel_id(), integer()| iodata(), timeout() | iodata()) ->
+ ok | {error, timeout} | {error, closed}.
+-spec send(pid(), channel_id(), integer(), iodata(), timeout()) ->
+ ok | {error, timeout} | {error, closed}.
%%
%%
%% Description: Sends channel data.
%%--------------------------------------------------------------------
-send(ConnectionManager, ChannelId, Data) ->
- send(ConnectionManager, ChannelId, 0, Data, infinity).
-send(ConnectionManager, ChannelId, Data, TimeOut) when is_integer(TimeOut) ->
- send(ConnectionManager, ChannelId, 0, Data, TimeOut);
-send(ConnectionManager, ChannelId, Data, infinity) ->
- send(ConnectionManager, ChannelId, 0, Data, infinity);
-send(ConnectionManager, ChannelId, Type, Data) ->
- send(ConnectionManager, ChannelId, Type, Data, infinity).
-send(ConnectionManager, ChannelId, Type, Data, TimeOut) ->
- ssh_connection_manager:send(ConnectionManager, ChannelId,
+send(ConnectionHandler, ChannelId, Data) ->
+ send(ConnectionHandler, ChannelId, 0, Data, infinity).
+send(ConnectionHandler, ChannelId, Data, TimeOut) when is_integer(TimeOut) ->
+ send(ConnectionHandler, ChannelId, 0, Data, TimeOut);
+send(ConnectionHandler, ChannelId, Data, infinity) ->
+ send(ConnectionHandler, ChannelId, 0, Data, infinity);
+send(ConnectionHandler, ChannelId, Type, Data) ->
+ send(ConnectionHandler, ChannelId, Type, Data, infinity).
+send(ConnectionHandler, ChannelId, Type, Data, TimeOut) ->
+ ssh_connection_handler:send(ConnectionHandler, ChannelId,
Type, Data, TimeOut).
%%--------------------------------------------------------------------
-%% Function: send_eof(ConnectionManager, ChannelId) ->
+-spec send_eof(pid(), channel_id()) -> ok | {error, closed}.
%%
%%
%% Description: Sends eof on the channel <ChannelId>.
%%--------------------------------------------------------------------
-send_eof(ConnectionManager, Channel) ->
- ssh_connection_manager:send_eof(ConnectionManager, Channel).
+send_eof(ConnectionHandler, Channel) ->
+ ssh_connection_handler:send_eof(ConnectionHandler, Channel).
%%--------------------------------------------------------------------
-%% Function: adjust_window(ConnectionManager, Channel, Bytes) ->
+-spec adjust_window(pid(), channel_id(), integer()) -> ok.
%%
%%
%% Description: Adjusts the ssh flowcontrol window.
%%--------------------------------------------------------------------
-adjust_window(ConnectionManager, Channel, Bytes) ->
- ssh_connection_manager:adjust_window(ConnectionManager, Channel, Bytes).
+adjust_window(ConnectionHandler, Channel, Bytes) ->
+ ssh_connection_handler:adjust_window(ConnectionHandler, Channel, Bytes).
%%--------------------------------------------------------------------
-%% Function: setenv(ConnectionManager, ChannelId, Var, Value, TimeOut) ->
+-spec setenv(pid(), channel_id(), string(), string(), timeout()) -> success | failure.
%%
%%
%% Description: Environment variables may be passed to the shell/command to be
%% started later.
%%--------------------------------------------------------------------
-setenv(ConnectionManager, ChannelId, Var, Value, TimeOut) ->
- ssh_connection_manager:request(ConnectionManager, ChannelId,
+setenv(ConnectionHandler, ChannelId, Var, Value, TimeOut) ->
+ ssh_connection_handler:request(ConnectionHandler, ChannelId,
"env", true, [?string(Var), ?string(Value)], TimeOut).
%%--------------------------------------------------------------------
-%% Function: close(ConnectionManager, ChannelId) ->
+-spec close(pid(), channel_id()) -> ok.
%%
%%
%% Description: Sends a close message on the channel <ChannelId>.
%%--------------------------------------------------------------------
-close(ConnectionManager, ChannelId) ->
- ssh_connection_manager:close(ConnectionManager, ChannelId).
-
+close(ConnectionHandler, ChannelId) ->
+ ssh_connection_handler:close(ConnectionHandler, ChannelId).
%%--------------------------------------------------------------------
-%% Function: reply_request(ConnectionManager, WantReply, Status, CannelId) ->_
+-spec reply_request(pid(), boolean(), success | failure, channel_id()) -> ok.
%%
%%
%% Description: Send status replies to requests that want such replies.
%%--------------------------------------------------------------------
-reply_request(ConnectionManager, true, Status, ChannelId) ->
- ssh_connection_manager:reply_request(ConnectionManager, Status, ChannelId),
- ok;
+reply_request(ConnectionHandler, true, Status, ChannelId) ->
+ ssh_connection_handler:reply_request(ConnectionHandler, Status, ChannelId);
reply_request(_,false, _, _) ->
ok.
-
%%--------------------------------------------------------------------
-%% Function: window_change(ConnectionManager, Channel, Width, Height) ->
-%%
-%%
-%% Description: Not yet officialy supported.
+%% Not yet officialy supported! The following functions are part of the
+%% initial contributed ssh application. They are untested. Do we want them?
+%% Should they be documented and tested?
%%--------------------------------------------------------------------
-window_change(ConnectionManager, Channel, Width, Height) ->
- window_change(ConnectionManager, Channel, Width, Height, 0, 0).
-window_change(ConnectionManager, Channel, Width, Height,
+window_change(ConnectionHandler, Channel, Width, Height) ->
+ window_change(ConnectionHandler, Channel, Width, Height, 0, 0).
+window_change(ConnectionHandler, Channel, Width, Height,
PixWidth, PixHeight) ->
- ssh_connection_manager:request(ConnectionManager, Channel,
+ ssh_connection_handler:request(ConnectionHandler, Channel,
"window-change", false,
[?uint32(Width), ?uint32(Height),
?uint32(PixWidth), ?uint32(PixHeight)], 0).
-%%--------------------------------------------------------------------
-%% Function: signal(ConnectionManager, Channel, Sig) ->
-%%
-%%
-%% Description: Not yet officialy supported.
-%%--------------------------------------------------------------------
-signal(ConnectionManager, Channel, Sig) ->
- ssh_connection_manager:request(ConnectionManager, Channel,
+
+signal(ConnectionHandler, Channel, Sig) ->
+ ssh_connection_handler:request(ConnectionHandler, Channel,
"signal", false, [?string(Sig)], 0).
-%%--------------------------------------------------------------------
-%% Function: signal(ConnectionManager, Channel, Status) ->
-%%
-%%
-%% Description: Not yet officialy supported.
-%%--------------------------------------------------------------------
-exit_status(ConnectionManager, Channel, Status) ->
- ssh_connection_manager:request(ConnectionManager, Channel,
- "exit-status", false, [?uint32(Status)], 0).
+exit_status(ConnectionHandler, Channel, Status) ->
+ ssh_connection_handler:request(ConnectionHandler, Channel,
+ "exit-status", false, [?uint32(Status)], 0).
-%%--------------------------------------------------------------------
-%% Function: open_pty(ConnectionManager, Channel, TimeOut) ->
-%%
-%%
-%% Description: Not yet officialy supported.
-%%--------------------------------------------------------------------
-open_pty(ConnectionManager, Channel, TimeOut) ->
- open_pty(ConnectionManager, Channel,
+open_pty(ConnectionHandler, Channel, TimeOut) ->
+ open_pty(ConnectionHandler, Channel,
os:getenv("TERM"), 80, 24, [], TimeOut).
-open_pty(ConnectionManager, Channel, Term, Width, Height, PtyOpts, TimeOut) ->
- open_pty(ConnectionManager, Channel, Term, Width,
+open_pty(ConnectionHandler, Channel, Term, Width, Height, PtyOpts, TimeOut) ->
+ open_pty(ConnectionHandler, Channel, Term, Width,
Height, 0, 0, PtyOpts, TimeOut).
-open_pty(ConnectionManager, Channel, Term, Width, Height,
+open_pty(ConnectionHandler, Channel, Term, Width, Height,
PixWidth, PixHeight, PtyOpts, TimeOut) ->
- ssh_connection_manager:request(ConnectionManager,
+ ssh_connection_handler:request(ConnectionHandler,
Channel, "pty-req", true,
[?string(Term),
?uint32(Width), ?uint32(Height),
?uint32(PixWidth),?uint32(PixHeight),
encode_pty_opts(PtyOpts)], TimeOut).
-
-%%--------------------------------------------------------------------
-%% Function: direct_tcpip(ConnectionManager, RemoteHost,
-%% RemotePort, OrigIP, OrigPort, Timeout) ->
-%%
-%%
-%% Description: Not yet officialy supported.
-%%--------------------------------------------------------------------
-direct_tcpip(ConnectionManager, RemoteHost,
+direct_tcpip(ConnectionHandler, RemoteHost,
RemotePort, OrigIP, OrigPort, Timeout) ->
- direct_tcpip(ConnectionManager, RemoteHost, RemotePort, OrigIP, OrigPort,
+ direct_tcpip(ConnectionHandler, RemoteHost, RemotePort, OrigIP, OrigPort,
?DEFAULT_WINDOW_SIZE, ?DEFAULT_PACKET_SIZE, Timeout).
-direct_tcpip(ConnectionManager, RemoteIP, RemotePort, OrigIP, OrigPort,
+direct_tcpip(ConnectionHandler, RemoteIP, RemotePort, OrigIP, OrigPort,
InitialWindowSize, MaxPacketSize, Timeout) ->
case {encode_ip(RemoteIP), encode_ip(OrigIP)} of
{false, _} ->
@@ -262,7 +235,7 @@ direct_tcpip(ConnectionManager, RemoteIP, RemotePort, OrigIP, OrigPort,
{_, false} ->
{error, einval};
{RIP, OIP} ->
- ssh_connection_manager:open_channel(ConnectionManager,
+ ssh_connection_handler:open_channel(ConnectionHandler,
"direct-tcpip",
[?string(RIP),
?uint32(RemotePort),
@@ -272,34 +245,24 @@ direct_tcpip(ConnectionManager, RemoteIP, RemotePort, OrigIP, OrigPort,
MaxPacketSize,
Timeout)
end.
-%%--------------------------------------------------------------------
-%% Function: tcpip_forward(ConnectionManager, BindIP, BindPort) ->
-%%
-%%
-%% Description: Not yet officialy supported.
-%%--------------------------------------------------------------------
-tcpip_forward(ConnectionManager, BindIP, BindPort) ->
+
+tcpip_forward(ConnectionHandler, BindIP, BindPort) ->
case encode_ip(BindIP) of
false ->
{error, einval};
IPStr ->
- ssh_connection_manager:global_request(ConnectionManager,
+ ssh_connection_handler:global_request(ConnectionHandler,
"tcpip-forward", true,
[?string(IPStr),
?uint32(BindPort)])
end.
-%%--------------------------------------------------------------------
-%% Function: cancel_tcpip_forward(ConnectionManager, BindIP, Port) ->
-%%
-%%
-%% Description: Not yet officialy supported.
-%%--------------------------------------------------------------------
-cancel_tcpip_forward(ConnectionManager, BindIP, Port) ->
+
+cancel_tcpip_forward(ConnectionHandler, BindIP, Port) ->
case encode_ip(BindIP) of
false ->
{error, einval};
IPStr ->
- ssh_connection_manager:global_request(ConnectionManager,
+ ssh_connection_handler:global_request(ConnectionHandler,
"cancel-tcpip-forward", true,
[?string(IPStr),
?uint32(Port)])
@@ -308,22 +271,23 @@ cancel_tcpip_forward(ConnectionManager, BindIP, Port) ->
%%--------------------------------------------------------------------
%%% Internal API
%%--------------------------------------------------------------------
-channel_data(ChannelId, DataType, Data, Connection, ConnectionPid, From)
+channel_data(ChannelId, DataType, Data, Connection, From)
when is_list(Data)->
channel_data(ChannelId, DataType,
- list_to_binary(Data), Connection, ConnectionPid, From);
+ list_to_binary(Data), Connection, From);
channel_data(ChannelId, DataType, Data,
- #connection{channel_cache = Cache} = Connection, ConnectionPid,
+ #connection{channel_cache = Cache} = Connection,
From) ->
case ssh_channel:cache_lookup(Cache, ChannelId) of
#channel{remote_id = Id, sent_close = false} = Channel0 ->
- {SendList, Channel} = update_send_window(Channel0#channel{flow_control = From}, DataType,
- Data, Connection),
+ {SendList, Channel} =
+ update_send_window(Channel0#channel{flow_control = From}, DataType,
+ Data, Connection),
Replies =
lists:map(fun({SendDataType, SendData}) ->
- {connection_reply, ConnectionPid,
+ {connection_reply,
channel_data_msg(Id,
SendDataType,
SendData)}
@@ -333,7 +297,7 @@ channel_data(ChannelId, DataType, Data,
Cache),
{{replies, Replies ++ FlowCtrlMsgs}, Connection};
_ ->
- gen_server:reply(From, {error, closed}),
+ gen_fsm:reply(From, {error, closed}),
{noreply, Connection}
end.
@@ -341,7 +305,7 @@ handle_msg(#ssh_msg_channel_open_confirmation{recipient_channel = ChannelId,
sender_channel = RemoteId,
initial_window_size = WindowSz,
maximum_packet_size = PacketSz},
- #connection{channel_cache = Cache} = Connection0, _, _) ->
+ #connection{channel_cache = Cache} = Connection0, _) ->
#channel{remote_id = undefined} = Channel =
ssh_channel:cache_lookup(Cache, ChannelId),
@@ -357,7 +321,7 @@ handle_msg(#ssh_msg_channel_open_failure{recipient_channel = ChannelId,
reason = Reason,
description = Descr,
lang = Lang},
- #connection{channel_cache = Cache} = Connection0, _, _) ->
+ #connection{channel_cache = Cache} = Connection0, _) ->
Channel = ssh_channel:cache_lookup(Cache, ChannelId),
ssh_channel:cache_delete(Cache, ChannelId),
{Reply, Connection} =
@@ -365,51 +329,59 @@ handle_msg(#ssh_msg_channel_open_failure{recipient_channel = ChannelId,
{{replies, [Reply]}, Connection};
handle_msg(#ssh_msg_channel_success{recipient_channel = ChannelId},
- #connection{channel_cache = Cache} = Connection0, _, _) ->
+ #connection{channel_cache = Cache} = Connection0, _) ->
Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- {Reply, Connection} = reply_msg(Channel, Connection0, success),
- {{replies, [Reply]}, Connection};
+ case reply_msg(Channel, Connection0, success) of
+ {[], Connection} ->
+ {noreply, Connection};
+ {Reply, Connection} ->
+ {{replies, [Reply]}, Connection}
+ end;
handle_msg(#ssh_msg_channel_failure{recipient_channel = ChannelId},
- #connection{channel_cache = Cache} = Connection0, _, _) ->
+ #connection{channel_cache = Cache} = Connection0, _) ->
Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- {Reply, Connection} = reply_msg(Channel, Connection0, failure),
- {{replies, [Reply]}, Connection};
+ case reply_msg(Channel, Connection0, failure) of
+ {[], Connection} ->
+ {noreply, Connection};
+ {Reply, Connection} ->
+ {{replies, [Reply]}, Connection}
+ end;
+
handle_msg(#ssh_msg_channel_eof{recipient_channel = ChannelId},
- #connection{channel_cache = Cache} = Connection0, _, _) ->
+ #connection{channel_cache = Cache} = Connection0, _) ->
Channel = ssh_channel:cache_lookup(Cache, ChannelId),
{Reply, Connection} = reply_msg(Channel, Connection0, {eof, ChannelId}),
{{replies, [Reply]}, Connection};
handle_msg(#ssh_msg_channel_close{recipient_channel = ChannelId},
- #connection{channel_cache = Cache} = Connection0,
- ConnectionPid, _) ->
+ #connection{channel_cache = Cache} = Connection0, _) ->
case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{sent_close = Closed, remote_id = RemoteId, flow_control = FlowControl} = Channel ->
+ #channel{sent_close = Closed, remote_id = RemoteId,
+ flow_control = FlowControl} = Channel ->
ssh_channel:cache_delete(Cache, ChannelId),
{CloseMsg, Connection} =
reply_msg(Channel, Connection0, {closed, ChannelId}),
-
- ConnReplyMsgs =
- case Closed of
- true -> [];
- false ->
- RemoteCloseMsg = channel_close_msg(RemoteId),
- [{connection_reply, ConnectionPid, RemoteCloseMsg}]
- end,
-
- %% if there was a send() in progress, make it fail
- SendReplyMsgs =
- case FlowControl of
- undefined -> [];
- From ->
- [{flow_control, From, {error, closed}}]
- end,
-
- Replies = ConnReplyMsgs ++ [CloseMsg] ++ SendReplyMsgs,
- {{replies, Replies}, Connection};
+ ConnReplyMsgs =
+ case Closed of
+ true -> [];
+ false ->
+ RemoteCloseMsg = channel_close_msg(RemoteId),
+ [{connection_reply, RemoteCloseMsg}]
+ end,
+
+ %% if there was a send() in progress, make it fail
+ SendReplyMsgs =
+ case FlowControl of
+ undefined -> [];
+ From ->
+ [{flow_control, From, {error, closed}}]
+ end,
+
+ Replies = ConnReplyMsgs ++ [CloseMsg] ++ SendReplyMsgs,
+ {{replies, Replies}, Connection};
undefined ->
{{replies, []}, Connection0}
@@ -417,21 +389,24 @@ handle_msg(#ssh_msg_channel_close{recipient_channel = ChannelId},
handle_msg(#ssh_msg_channel_data{recipient_channel = ChannelId,
data = Data},
- #connection{channel_cache = Cache} = Connection0, _, _) ->
+ #connection{channel_cache = Cache} = Connection0, _) ->
- #channel{recv_window_size = Size} = Channel =
- ssh_channel:cache_lookup(Cache, ChannelId),
- WantedSize = Size - size(Data),
- ssh_channel:cache_update(Cache, Channel#channel{
- recv_window_size = WantedSize}),
- {Replies, Connection} =
- channel_data_reply(Cache, Channel, Connection0, 0, Data),
- {{replies, Replies}, Connection};
+ case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{recv_window_size = Size} = Channel ->
+ WantedSize = Size - size(Data),
+ ssh_channel:cache_update(Cache, Channel#channel{
+ recv_window_size = WantedSize}),
+ {Replies, Connection} =
+ channel_data_reply(Cache, Channel, Connection0, 0, Data),
+ {{replies, Replies}, Connection};
+ undefined ->
+ {noreply, Connection0}
+ end;
handle_msg(#ssh_msg_channel_extended_data{recipient_channel = ChannelId,
data_type_code = DataType,
data = Data},
- #connection{channel_cache = Cache} = Connection0, _, _) ->
+ #connection{channel_cache = Cache} = Connection0, _) ->
#channel{recv_window_size = Size} = Channel =
ssh_channel:cache_lookup(Cache, ChannelId),
@@ -444,9 +419,7 @@ handle_msg(#ssh_msg_channel_extended_data{recipient_channel = ChannelId,
handle_msg(#ssh_msg_channel_window_adjust{recipient_channel = ChannelId,
bytes_to_add = Add},
- #connection{channel_cache = Cache} = Connection,
- ConnectionPid, _) ->
-
+ #connection{channel_cache = Cache} = Connection, _) ->
#channel{send_window_size = Size, remote_id = RemoteId} =
Channel0 = ssh_channel:cache_lookup(Cache, ChannelId),
@@ -455,8 +428,7 @@ handle_msg(#ssh_msg_channel_window_adjust{recipient_channel = ChannelId,
0, undefined, Connection),
Replies = lists:map(fun({Type, Data}) ->
- {connection_reply, ConnectionPid,
- channel_data_msg(RemoteId, Type, Data)}
+ {connection_reply, channel_data_msg(RemoteId, Type, Data)}
end, SendList),
FlowCtrlMsgs = flow_control(Channel, Cache),
{{replies, Replies ++ FlowCtrlMsgs}, Connection};
@@ -464,10 +436,9 @@ handle_msg(#ssh_msg_channel_window_adjust{recipient_channel = ChannelId,
handle_msg(#ssh_msg_channel_open{channel_type = "session" = Type,
sender_channel = RemoteId,
initial_window_size = WindowSz,
- maximum_packet_size = PacketSz}, Connection0,
- ConnectionPid, server) ->
+ maximum_packet_size = PacketSz}, Connection0, server) ->
- try setup_session(Connection0, ConnectionPid, RemoteId,
+ try setup_session(Connection0, RemoteId,
Type, WindowSz, PacketSz) of
Result ->
Result
@@ -475,20 +446,20 @@ handle_msg(#ssh_msg_channel_open{channel_type = "session" = Type,
FailMsg = channel_open_failure_msg(RemoteId,
?SSH_OPEN_CONNECT_FAILED,
"Connection refused", "en"),
- {{replies, [{connection_reply, ConnectionPid, FailMsg}]},
+ {{replies, [{connection_reply, FailMsg}]},
Connection0}
end;
handle_msg(#ssh_msg_channel_open{channel_type = "session",
sender_channel = RemoteId},
- Connection, ConnectionPid, client) ->
+ Connection, client) ->
%% Client implementations SHOULD reject any session channel open
%% requests to make it more difficult for a corrupt server to attack the
%% client. See See RFC 4254 6.1.
FailMsg = channel_open_failure_msg(RemoteId,
?SSH_OPEN_CONNECT_FAILED,
"Connection refused", "en"),
- {{replies, [{connection_reply, ConnectionPid, FailMsg}]},
+ {{replies, [{connection_reply, FailMsg}]},
Connection};
handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip" = Type,
@@ -496,8 +467,7 @@ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip" = Type,
initial_window_size = RWindowSz,
maximum_packet_size = RPacketSz,
data = Data},
- #connection{channel_cache = Cache} = Connection0,
- ConnectionPid, server) ->
+ #connection{channel_cache = Cache} = Connection0, server) ->
<<?UINT32(ALen), Address:ALen/binary, ?UINT32(Port),
?UINT32(OLen), Orig:OLen/binary, ?UINT32(OrigPort)>> = Data,
@@ -507,7 +477,7 @@ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip" = Type,
?SSH_OPEN_CONNECT_FAILED,
"Connection refused", "en"),
{{replies,
- [{connection_reply, ConnectionPid, FailMsg}]}, Connection0};
+ [{connection_reply, FailMsg}]}, Connection0};
ChannelPid ->
{ChannelId, Connection1} = new_channel_id(Connection0),
LWindowSz = ?DEFAULT_WINDOW_SIZE,
@@ -528,32 +498,31 @@ handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip" = Type,
{open, Channel, {forwarded_tcpip,
decode_ip(Address), Port,
decode_ip(Orig), OrigPort}}),
- {{replies, [{connection_reply, ConnectionPid, OpenConfMsg},
+ {{replies, [{connection_reply, OpenConfMsg},
OpenMsg]}, Connection}
end;
handle_msg(#ssh_msg_channel_open{channel_type = "forwarded-tcpip",
sender_channel = RemoteId},
- Connection, ConnectionPid, client) ->
+ Connection, client) ->
%% Client implementations SHOULD reject direct TCP/IP open requests for
%% security reasons. See RFC 4254 7.2.
FailMsg = channel_open_failure_msg(RemoteId,
?SSH_OPEN_CONNECT_FAILED,
"Connection refused", "en"),
- {{replies, [{connection_reply, ConnectionPid, FailMsg}]}, Connection};
+ {{replies, [{connection_reply, FailMsg}]}, Connection};
-handle_msg(#ssh_msg_channel_open{sender_channel = RemoteId}, Connection,
- ConnectionPid, _) ->
+handle_msg(#ssh_msg_channel_open{sender_channel = RemoteId}, Connection, _) ->
FailMsg = channel_open_failure_msg(RemoteId,
?SSH_OPEN_ADMINISTRATIVELY_PROHIBITED,
"Not allowed", "en"),
- {{replies, [{connection_reply, ConnectionPid, FailMsg}]}, Connection};
+ {{replies, [{connection_reply, FailMsg}]}, Connection};
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "exit-status",
data = Data},
- #connection{channel_cache = Cache} = Connection, _, _) ->
+ #connection{channel_cache = Cache} = Connection, _) ->
<<?UINT32(Status)>> = Data,
Channel = ssh_channel:cache_lookup(Cache, ChannelId),
{Reply, Connection} =
@@ -564,8 +533,7 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "exit-signal",
want_reply = false,
data = Data},
- #connection{channel_cache = Cache} = Connection0,
- ConnectionPid, _) ->
+ #connection{channel_cache = Cache} = Connection0, _) ->
<<?UINT32(SigLen), SigName:SigLen/binary,
?BOOLEAN(_Core),
?UINT32(ErrLen), Err:ErrLen/binary,
@@ -578,14 +546,14 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
binary_to_list(Err),
binary_to_list(Lang)}),
CloseMsg = channel_close_msg(RemoteId),
- {{replies, [{connection_reply, ConnectionPid, CloseMsg}, Reply]},
+ {{replies, [{connection_reply, CloseMsg}, Reply]},
Connection};
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "xon-xoff",
want_reply = false,
data = Data},
- #connection{channel_cache = Cache} = Connection, _, _) ->
+ #connection{channel_cache = Cache} = Connection, _) ->
<<?BOOLEAN(CDo)>> = Data,
Channel = ssh_channel:cache_lookup(Cache, ChannelId),
{Reply, Connection} =
@@ -596,7 +564,7 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "window-change",
want_reply = false,
data = Data},
- #connection{channel_cache = Cache} = Connection0, _, _) ->
+ #connection{channel_cache = Cache} = Connection0, _) ->
<<?UINT32(Width),?UINT32(Height),
?UINT32(PixWidth), ?UINT32(PixHeight)>> = Data,
Channel = ssh_channel:cache_lookup(Cache, ChannelId),
@@ -609,7 +577,7 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "signal",
data = Data},
- #connection{channel_cache = Cache} = Connection0, _, _) ->
+ #connection{channel_cache = Cache} = Connection0, _) ->
<<?UINT32(SigLen), SigName:SigLen/binary>> = Data,
Channel = ssh_channel:cache_lookup(Cache, ChannelId),
@@ -622,8 +590,7 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "subsystem",
want_reply = WantReply,
data = Data},
- #connection{channel_cache = Cache} = Connection,
- ConnectionPid, server) ->
+ #connection{channel_cache = Cache} = Connection, server) ->
<<?UINT32(SsLen), SsName:SsLen/binary>> = Data,
#channel{remote_id = RemoteId} = Channel0 =
@@ -631,22 +598,23 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
ReplyMsg = {subsystem, ChannelId, WantReply, binary_to_list(SsName)},
- try start_subsytem(SsName, Connection, Channel0, ReplyMsg) of
- {ok, Pid} ->
- erlang:monitor(process, Pid),
- Channel = Channel0#channel{user = Pid},
- ssh_channel:cache_update(Cache, Channel),
- Reply = {connection_reply, ConnectionPid,
- channel_success_msg(RemoteId)},
- {{replies, [Reply]}, Connection}
- catch _:_ ->
- Reply = {connection_reply, ConnectionPid,
- channel_failure_msg(RemoteId)},
- {{replies, [Reply]}, Connection}
+ try
+ {ok, Pid} = start_subsytem(SsName, Connection, Channel0, ReplyMsg),
+ erlang:monitor(process, Pid),
+ Channel = Channel0#channel{user = Pid},
+ ssh_channel:cache_update(Cache, Channel),
+ Reply = {connection_reply,
+ channel_success_msg(RemoteId)},
+ {{replies, [Reply]}, Connection}
+ catch
+ _:_ ->
+ ErrorReply = {connection_reply,
+ channel_failure_msg(RemoteId)},
+ {{replies, [ErrorReply]}, Connection}
end;
handle_msg(#ssh_msg_channel_request{request_type = "subsystem"},
- Connection, _, client) ->
+ Connection, client) ->
%% The client SHOULD ignore subsystem requests. See RFC 4254 6.5.
{{replies, []}, Connection};
@@ -654,8 +622,7 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "pty-req",
want_reply = WantReply,
data = Data},
- #connection{channel_cache = Cache} = Connection,
- ConnectionPid, server) ->
+ #connection{channel_cache = Cache} = Connection, server) ->
<<?UINT32(TermLen), BTermName:TermLen/binary,
?UINT32(Width),?UINT32(Height),
?UINT32(PixWidth), ?UINT32(PixHeight),
@@ -667,27 +634,26 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- handle_cli_msg(Connection, ConnectionPid, Channel,
+ handle_cli_msg(Connection, Channel,
{pty, ChannelId, WantReply, PtyRequest});
handle_msg(#ssh_msg_channel_request{request_type = "pty-req"},
- Connection, _, client) ->
+ Connection, client) ->
%% The client SHOULD ignore pty requests. See RFC 4254 6.2.
{{replies, []}, Connection};
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "shell",
want_reply = WantReply},
- #connection{channel_cache = Cache} = Connection,
- ConnectionPid, server) ->
+ #connection{channel_cache = Cache} = Connection, server) ->
Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- handle_cli_msg(Connection, ConnectionPid, Channel,
+ handle_cli_msg(Connection, Channel,
{shell, ChannelId, WantReply});
handle_msg(#ssh_msg_channel_request{request_type = "shell"},
- Connection, _, client) ->
+ Connection, client) ->
%% The client SHOULD ignore shell requests. See RFC 4254 6.5.
{{replies, []}, Connection};
@@ -695,17 +661,16 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "exec",
want_reply = WantReply,
data = Data},
- #connection{channel_cache = Cache} = Connection,
- ConnectionPid, server) ->
+ #connection{channel_cache = Cache} = Connection, server) ->
<<?UINT32(Len), Command:Len/binary>> = Data,
Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- handle_cli_msg(Connection, ConnectionPid, Channel,
+ handle_cli_msg(Connection, Channel,
{exec, ChannelId, WantReply, binary_to_list(Command)});
handle_msg(#ssh_msg_channel_request{request_type = "exec"},
- Connection, _, client) ->
+ Connection, client) ->
%% The client SHOULD ignore exec requests. See RFC 4254 6.5.
{{replies, []}, Connection};
@@ -713,31 +678,30 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = "env",
want_reply = WantReply,
data = Data},
- #connection{channel_cache = Cache} = Connection,
- ConnectionPid, server) ->
+ #connection{channel_cache = Cache} = Connection, server) ->
<<?UINT32(VarLen),
Var:VarLen/binary, ?UINT32(ValueLen), Value:ValueLen/binary>> = Data,
Channel = ssh_channel:cache_lookup(Cache, ChannelId),
- handle_cli_msg(Connection, ConnectionPid, Channel,
+ handle_cli_msg(Connection, Channel,
{env, ChannelId, WantReply, Var, Value});
handle_msg(#ssh_msg_channel_request{request_type = "env"},
- Connection, _, client) ->
+ Connection, client) ->
%% The client SHOULD ignore env requests.
{{replies, []}, Connection};
handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
request_type = _Other,
- want_reply = WantReply}, #connection{channel_cache = Cache} = Connection,
- ConnectionPid, _) ->
+ want_reply = WantReply},
+ #connection{channel_cache = Cache} = Connection, _) ->
if WantReply == true ->
case ssh_channel:cache_lookup(Cache, ChannelId) of
#channel{remote_id = RemoteId} ->
FailMsg = channel_failure_msg(RemoteId),
- {{replies, [{connection_reply, ConnectionPid, FailMsg}]},
+ {{replies, [{connection_reply, FailMsg}]},
Connection};
undefined -> %% Chanel has been closed
{noreply, Connection}
@@ -748,61 +712,75 @@ handle_msg(#ssh_msg_channel_request{recipient_channel = ChannelId,
handle_msg(#ssh_msg_global_request{name = _Type,
want_reply = WantReply,
- data = _Data}, Connection,
- ConnectionPid, _) ->
+ data = _Data}, Connection, _) ->
if WantReply == true ->
FailMsg = request_failure_msg(),
- {{replies, [{connection_reply, ConnectionPid, FailMsg}]},
+ {{replies, [{connection_reply, FailMsg}]},
Connection};
true ->
{noreply, Connection}
end;
+handle_msg(#ssh_msg_request_failure{},
+ #connection{requests = [{_, From} | Rest]} = Connection, _) ->
+ {{replies, [{channel_requst_reply, From, {failure, <<>>}}]},
+ Connection#connection{requests = Rest}};
+handle_msg(#ssh_msg_request_success{data = Data},
+ #connection{requests = [{_, From} | Rest]} = Connection, _) ->
+ {{replies, [{channel_requst_reply, From, {success, Data}}]},
+ Connection#connection{requests = Rest}};
+
%%% This transport message will also be handled at the connection level
handle_msg(#ssh_msg_disconnect{code = Code,
description = Description,
language = _Lang },
- #connection{channel_cache = Cache} = Connection0, _, _) ->
+ #connection{channel_cache = Cache} = Connection0, _) ->
{Connection, Replies} =
ssh_channel:cache_foldl(fun(Channel, {Connection1, Acc}) ->
{Reply, Connection2} =
reply_msg(Channel,
- Connection1, {closed, Channel#channel.local_id}),
+ Connection1,
+ {closed, Channel#channel.local_id}),
{Connection2, [Reply | Acc]}
end, {Connection0, []}, Cache),
ssh_channel:cache_delete(Cache),
{disconnect, {Code, Description}, {{replies, Replies}, Connection}}.
-handle_cli_msg(#connection{channel_cache = Cache} = Connection0,
- ConnectionPid,
+handle_cli_msg(#connection{channel_cache = Cache} = Connection,
#channel{user = undefined,
+ remote_id = RemoteId,
local_id = ChannelId} = Channel0, Reply0) ->
- case (catch start_cli(Connection0, ChannelId)) of
+ case (catch start_cli(Connection, ChannelId)) of
{ok, Pid} ->
erlang:monitor(process, Pid),
Channel = Channel0#channel{user = Pid},
ssh_channel:cache_update(Cache, Channel),
- {Reply, Connection} = reply_msg(Channel, Connection0, Reply0),
- {{replies, [Reply]}, Connection};
- _ ->
- Reply = {connection_reply, ConnectionPid,
- request_failure_msg()},
- {{replies, [Reply]}, Connection0}
+ Reply = {connection_reply,
+ channel_success_msg(RemoteId)},
+ {{replies, [{channel_data, Pid, Reply0}, Reply]}, Connection};
+ _Other ->
+ Reply = {connection_reply,
+ channel_failure_msg(RemoteId)},
+ {{replies, [Reply]}, Connection}
end;
-handle_cli_msg(Connection0, _, Channel, Reply0) ->
+handle_cli_msg(Connection0, Channel, Reply0) ->
{Reply, Connection} = reply_msg(Channel, Connection0, Reply0),
{{replies, [Reply]}, Connection}.
-
channel_eof_msg(ChannelId) ->
#ssh_msg_channel_eof{recipient_channel = ChannelId}.
channel_close_msg(ChannelId) ->
#ssh_msg_channel_close {recipient_channel = ChannelId}.
+channel_status_msg({success, ChannelId}) ->
+ channel_success_msg(ChannelId);
+channel_status_msg({failure, ChannelId}) ->
+ channel_failure_msg(ChannelId).
+
channel_success_msg(ChannelId) ->
#ssh_msg_channel_success{recipient_channel = ChannelId}.
@@ -880,70 +858,6 @@ bound_channel(IP, Port, Connection) ->
_ -> undefined
end.
-messages() ->
- [ {ssh_msg_global_request, ?SSH_MSG_GLOBAL_REQUEST,
- [string,
- boolean,
- '...']},
-
- {ssh_msg_request_success, ?SSH_MSG_REQUEST_SUCCESS,
- ['...']},
-
- {ssh_msg_request_failure, ?SSH_MSG_REQUEST_FAILURE,
- []},
-
- {ssh_msg_channel_open, ?SSH_MSG_CHANNEL_OPEN,
- [string,
- uint32,
- uint32,
- uint32,
- '...']},
-
- {ssh_msg_channel_open_confirmation, ?SSH_MSG_CHANNEL_OPEN_CONFIRMATION,
- [uint32,
- uint32,
- uint32,
- uint32,
- '...']},
-
- {ssh_msg_channel_open_failure, ?SSH_MSG_CHANNEL_OPEN_FAILURE,
- [uint32,
- uint32,
- string,
- string]},
-
- {ssh_msg_channel_window_adjust, ?SSH_MSG_CHANNEL_WINDOW_ADJUST,
- [uint32,
- uint32]},
-
- {ssh_msg_channel_data, ?SSH_MSG_CHANNEL_DATA,
- [uint32,
- binary]},
-
- {ssh_msg_channel_extended_data, ?SSH_MSG_CHANNEL_EXTENDED_DATA,
- [uint32,
- uint32,
- binary]},
-
- {ssh_msg_channel_eof, ?SSH_MSG_CHANNEL_EOF,
- [uint32]},
-
- {ssh_msg_channel_close, ?SSH_MSG_CHANNEL_CLOSE,
- [uint32]},
-
- {ssh_msg_channel_request, ?SSH_MSG_CHANNEL_REQUEST,
- [uint32,
- string,
- boolean,
- '...']},
-
- {ssh_msg_channel_success, ?SSH_MSG_CHANNEL_SUCCESS,
- [uint32]},
-
- {ssh_msg_channel_failure, ?SSH_MSG_CHANNEL_FAILURE,
- [uint32]}
- ].
-
encode_ip(Addr) when is_tuple(Addr) ->
case catch inet_parse:ntoa(Addr) of
{'EXIT',_} -> false;
@@ -965,14 +879,14 @@ start_channel(Cb, Id, Args, SubSysSup) ->
start_channel(Cb, Id, Args, SubSysSup, Exec) ->
ChildSpec = child_spec(Cb, Id, Args, Exec),
- ChannelSup =ssh_subsystem_sup:channel_supervisor(SubSysSup),
+ ChannelSup = ssh_subsystem_sup:channel_supervisor(SubSysSup),
ssh_channel_sup:start_child(ChannelSup, ChildSpec).
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
setup_session(#connection{channel_cache = Cache} = Connection0,
- ConnectionPid, RemoteId,
+ RemoteId,
Type, WindowSize, PacketSize) ->
{ChannelId, Connection} = new_channel_id(Connection0),
@@ -990,7 +904,7 @@ setup_session(#connection{channel_cache = Cache} = Connection0,
?DEFAULT_WINDOW_SIZE,
?DEFAULT_PACKET_SIZE),
- {{replies, [{connection_reply, ConnectionPid, OpenConfMsg}]}, Connection}.
+ {{replies, [{connection_reply, OpenConfMsg}]}, Connection}.
check_subsystem("sftp"= SsName, Options) ->
@@ -1019,35 +933,21 @@ child_spec(Callback, Id, Args, Exec) ->
Type = worker,
{Name, StartFunc, Restart, Shutdown, Type, [ssh_channel]}.
-%% Backwards compatibility
-start_cli(#connection{address = Address, port = Port, cli_spec = {Fun, [Shell]},
- options = Options},
- _ChannelId) when is_function(Fun) ->
- case Fun(Shell, Address, Port, Options) of
- NewFun when is_function(NewFun) ->
- {ok, NewFun()};
- Pid when is_pid(Pid) ->
- {ok, Pid}
- end;
-
+start_cli(#connection{cli_spec = no_cli}, _) ->
+ {error, cli_disabled};
start_cli(#connection{cli_spec = {CbModule, Args}, exec = Exec,
sub_system_supervisor = SubSysSup}, ChannelId) ->
start_channel(CbModule, ChannelId, Args, SubSysSup, Exec).
-start_subsytem(BinName, #connection{address = Address, port = Port,
- options = Options,
+start_subsytem(BinName, #connection{options = Options,
sub_system_supervisor = SubSysSup},
- #channel{local_id = ChannelId, remote_id = RemoteChannelId},
- ReplyMsg) ->
+ #channel{local_id = ChannelId}, _ReplyMsg) ->
Name = binary_to_list(BinName),
case check_subsystem(Name, Options) of
{Callback, Opts} when is_atom(Callback), Callback =/= none ->
start_channel(Callback, ChannelId, Opts, SubSysSup);
{Other, _} when Other =/= none ->
- handle_backwards_compatibility(Other, self(),
- ChannelId, RemoteChannelId,
- Options, Address, Port,
- {ssh_cm, self(), ReplyMsg})
+ {error, legacy_option_not_supported}
end.
channel_data_reply(_, #channel{local_id = ChannelId} = Channel,
@@ -1070,9 +970,12 @@ reply_msg(Channel, Connection, failure = Reply) ->
request_reply_or_data(Channel, Connection, Reply);
reply_msg(Channel, Connection, {closed, _} = Reply) ->
request_reply_or_data(Channel, Connection, Reply);
+reply_msg(undefined, Connection, _Reply) ->
+ {noreply, Connection};
reply_msg(#channel{user = ChannelPid}, Connection, Reply) ->
{{channel_data, ChannelPid, Reply}, Connection}.
+
request_reply_or_data(#channel{local_id = ChannelId, user = ChannelPid},
#connection{requests = Requests} =
Connection, Reply) ->
@@ -1080,10 +983,13 @@ request_reply_or_data(#channel{local_id = ChannelId, user = ChannelPid},
{value, {ChannelId, From}} ->
{{channel_requst_reply, From, Reply},
Connection#connection{requests =
- lists:keydelete(ChannelId, 1, Requests)}};
+ lists:keydelete(ChannelId, 1, Requests)}};
+ false when (Reply == success) or (Reply == failure) ->
+ {[], Connection};
false ->
{{channel_data, ChannelPid, Reply}, Connection}
end.
+
update_send_window(Channel, _, undefined,
#connection{channel_cache = Cache}) ->
do_update_send_window(Channel, Channel#channel.send_buf, Cache);
@@ -1139,7 +1045,7 @@ flow_control([], Channel, Cache) ->
[];
flow_control([_|_], #channel{flow_control = From,
- send_buf = []} = Channel, Cache) when From =/= undefined ->
+ send_buf = []} = Channel, Cache) when From =/= undefined ->
[{flow_control, Cache, Channel, From, ok}];
flow_control(_,_,_) ->
[].
@@ -1341,43 +1247,3 @@ decode_ip(Addr) when is_binary(Addr) ->
{ok,A} -> A
end.
-%% This is really awful and that is why it is beeing phased out.
-handle_backwards_compatibility({_,_,_,_,_,_} = ChildSpec, _, _, _, _,
- Address, Port, _) ->
- SystemSup = ssh_system_sup:system_supervisor(Address, Port),
- ChannelSup = ssh_system_sup:channel_supervisor(SystemSup),
- ssh_channel_sup:start_child(ChannelSup, ChildSpec);
-
-handle_backwards_compatibility(Module, ConnectionManager, ChannelId,
- RemoteChannelId, Opts,
- _, _, Msg) when is_atom(Module) ->
- {ok, SubSystemPid} = gen_server:start_link(Module, [Opts], []),
- SubSystemPid !
- {ssh_cm, ConnectionManager,
- {open, ChannelId, RemoteChannelId, {session}}},
- SubSystemPid ! Msg,
- {ok, SubSystemPid};
-
-handle_backwards_compatibility(Fun, ConnectionManager, ChannelId,
- RemoteChannelId,
- _, _, _, Msg) when is_function(Fun) ->
- SubSystemPid = Fun(),
- SubSystemPid !
- {ssh_cm, ConnectionManager,
- {open, ChannelId, RemoteChannelId, {session}}},
- SubSystemPid ! Msg,
- {ok, SubSystemPid};
-
-handle_backwards_compatibility(ChildSpec,
- ConnectionManager,
- ChannelId, RemoteChannelId, _,
- Address, Port, Msg) ->
- SystemSup = ssh_system_sup:system_supervisor(Address, Port),
- ChannelSup = ssh_system_sup:channel_supervisor(SystemSup),
- {ok, SubSystemPid}
- = ssh_channel_sup:start_child(ChannelSup, ChildSpec),
- SubSystemPid !
- {ssh_cm, ConnectionManager,
- {open, ChannelId, RemoteChannelId, {session}}},
- SubSystemPid ! Msg,
- {ok, SubSystemPid}.
diff --git a/lib/ssh/src/ssh_connection_controler.erl b/lib/ssh/src/ssh_connection_controler.erl
deleted file mode 100644
index ca3e62dc83..0000000000
--- a/lib/ssh/src/ssh_connection_controler.erl
+++ /dev/null
@@ -1,137 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2009-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 : ssh_connection_controler.erl
-%% Description :
-%%
-%%--------------------------------------------------------------------
-
--module(ssh_connection_controler).
-
--behaviour(gen_server).
-
-%%-----------------------------------------------------------------
-%% External exports
-%%-----------------------------------------------------------------
--export([start_link/1, start_handler_child/2, start_manager_child/2,
- connection_manager/1]).
-
-%%-----------------------------------------------------------------
-%% Internal exports
-%%-----------------------------------------------------------------
--export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- code_change/3, terminate/2, stop/1]).
-
--record(state, {role, manager, handler, timeout}).
-
-%%-----------------------------------------------------------------
-%% External interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: start/0
-%%-----------------------------------------------------------------
-start_link(Args) ->
- gen_server:start_link(?MODULE, [Args], []).
-
-%% Will be called from the manager child process
-start_handler_child(ServerRef, Args) ->
- gen_server:call(ServerRef, {handler, self(), Args}, infinity).
-
-%% Will be called from the acceptor process
-start_manager_child(ServerRef, Args) ->
- gen_server:call(ServerRef, {manager, Args}, infinity).
-
-connection_manager(ServerRef) ->
- {ok, gen_server:call(ServerRef, manager, infinity)}.
-
-%%-----------------------------------------------------------------
-%% Internal interface functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: stop/1
-%%-----------------------------------------------------------------
-stop(Pid) ->
- gen_server:cast(Pid, stop).
-
-%%-----------------------------------------------------------------
-%% Server functions
-%%-----------------------------------------------------------------
-%%-----------------------------------------------------------------
-%% Func: init/1
-%%-----------------------------------------------------------------
-init([Opts]) ->
- process_flag(trap_exit, true),
- case proplists:get_value(role, Opts) of
- client ->
- {ok, Manager} = ssh_connection_manager:start_link([client, Opts]),
- {ok, #state{role = client, manager = Manager}};
- _server ->
- %% Children started by acceptor process
- {ok, #state{role = server}}
- end.
-
-
-%%-----------------------------------------------------------------
-%% Func: terminate/2
-%%-----------------------------------------------------------------
-terminate(_Reason, #state{}) ->
- ok.
-
-%%-----------------------------------------------------------------
-%% Func: handle_call/3
-%%-----------------------------------------------------------------
-handle_call({handler, Pid, [Role, Socket, Opts]}, _From, State) ->
- {ok, Handler} = ssh_connection_handler:start_link(Role, Pid, Socket, Opts),
- {reply, {ok, Handler}, State#state{handler = Handler}};
-handle_call({manager, [server = Role, Socket, Opts, SubSysSup]}, _From, State) ->
- {ok, Manager} = ssh_connection_manager:start_link([Role, Socket, Opts, SubSysSup]),
- {reply, {ok, Manager}, State#state{manager = Manager}};
-handle_call({manager, [client = Role | Opts]}, _From, State) ->
- {ok, Manager} = ssh_connection_manager:start_link([Role, Opts]),
- {reply, {ok, Manager}, State#state{manager = Manager}};
-handle_call(manager, _From, State) ->
- {reply, State#state.manager, State};
-handle_call(stop, _From, State) ->
- {stop, normal, ok, State};
-handle_call(_, _, State) ->
- {noreply, State, State#state.timeout}.
-
-%%-----------------------------------------------------------------
-%% Func: handle_cast/2
-%%-----------------------------------------------------------------
-handle_cast(stop, State) ->
- {stop, normal, State};
-handle_cast(_, State) ->
- {noreply, State, State#state.timeout}.
-
-%%-----------------------------------------------------------------
-%% Func: handle_info/2
-%%-----------------------------------------------------------------
-%% handle_info(ssh_connected, State) ->
-%% {stop, normal, State};
-%% Servant termination.
-handle_info({'EXIT', _Pid, Reason}, State) ->
- {stop, Reason, State}.
-
-%%-----------------------------------------------------------------
-%% Func: code_change/3
-%%-----------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 9de4dd5967..7ba2179a76 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -18,10 +18,11 @@
%%
%%
%%----------------------------------------------------------------------
-%% Purpose: Handles the setup of an ssh connection, e.i. both the
-%% setup SSH Transport Layer Protocol (RFC 4253) and Authentication
-%% Protocol (RFC 4252). Details of the different protocols are
-%% implemented in ssh_transport.erl, ssh_auth.erl
+%% Purpose: Handles an ssh connection, e.i. both the
+%% setup SSH Transport Layer Protocol (RFC 4253), Authentication
+%% Protocol (RFC 4252) and SSH connection Protocol (RFC 4255)
+%% Details of the different protocols are
+%% implemented in ssh_transport.erl, ssh_auth.erl and ssh_connection.erl
%% ----------------------------------------------------------------------
-module(ssh_connection_handler).
@@ -33,10 +34,14 @@
-include("ssh_auth.hrl").
-include("ssh_connect.hrl").
--export([start_link/4, send/2, renegotiate/1, send_event/2,
- connection_info/3,
- peer_address/1,
- renegotiate_data/1]).
+-export([start_link/3]).
+
+%% Internal application API
+-export([open_channel/6, reply_request/3, request/6, request/7,
+ global_request/4, send/5, send_eof/2, info/1, info/2,
+ connection_info/2, channel_info/3,
+ adjust_window/3, close/2, stop/1, renegotiate/1, renegotiate_data/1,
+ start_connection/4]).
%% gen_fsm callbacks
-export([hello/2, kexinit/2, key_exchange/2, new_keys/2,
@@ -45,10 +50,14 @@
-export([init/1, handle_event/3,
handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).
-%% spawn export
--export([ssh_info_handler/3]).
-
-record(state, {
+ role,
+ client,
+ starter,
+ auth_user,
+ connection_state,
+ latest_channel_id = 0,
+ idle_timer_ref,
transport_protocol, % ex: tcp
transport_cb,
transport_close_tag,
@@ -59,105 +68,234 @@
undecoded_packet_length, % integer()
key_exchange_init_msg, % #ssh_msg_kexinit{}
renegotiate = false, % boolean()
- manager, % pid()
connection_queue,
address,
port,
opts
}).
--define(DBG_MESSAGE, true).
+-type state_name() :: hello | kexinit | key_exchange | new_keys | userauth | connection.
+-type gen_fsm_state_return() :: {next_state, state_name(), term()} |
+ {next_state, state_name(), term(), timeout()} |
+ {stop, term(), term()}.
%%====================================================================
%% Internal application API
%%====================================================================
+
%%--------------------------------------------------------------------
-%% Function: start_link() -> ok,Pid} | ignore | {error,Error}
-%% Description:Creates a gen_fsm process which calls Module:init/1 to
-%% initialize. To ensure a synchronized start-up procedure, this function
-%% does not return until Module:init/1 has returned.
+-spec start_connection(client| server, port(), proplists:proplist(),
+ timeout()) -> {ok, pid()} | {error, term()}.
%%--------------------------------------------------------------------
-start_link(Role, Manager, Socket, Options) ->
- gen_fsm:start_link(?MODULE, [Role, Manager, Socket, Options], []).
-
-send(ConnectionHandler, Data) ->
- send_all_state_event(ConnectionHandler, {send, Data}).
+start_connection(client = Role, Socket, Options, Timeout) ->
+ try
+ {ok, Pid} = sshc_sup:start_child([Role, Socket, Options]),
+ {_, Callback, _} =
+ proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}),
+ ok = socket_control(Socket, Pid, Callback),
+ Ref = erlang:monitor(process, Pid),
+ handshake(Pid, Ref, Timeout)
+ catch
+ exit:{noproc, _} ->
+ {error, ssh_not_started};
+ _:Error ->
+ {error, Error}
+ end;
-renegotiate(ConnectionHandler) ->
- send_all_state_event(ConnectionHandler, renegotiate).
-
-renegotiate_data(ConnectionHandler) ->
- send_all_state_event(ConnectionHandler, data_size).
-connection_info(ConnectionHandler, From, Options) ->
- send_all_state_event(ConnectionHandler, {info, From, Options}).
+start_connection(server = Role, Socket, Options, Timeout) ->
+ try
+ Sups = proplists:get_value(supervisors, Options),
+ ConnectionSup = proplists:get_value(connection_sup, Sups),
+ Opts = [{supervisors, Sups}, {user_pid, self()} | proplists:get_value(ssh_opts, Options, [])],
+ {ok, Pid} = ssh_connection_sup:start_child(ConnectionSup, [Role, Socket, Opts]),
+ {_, Callback, _} = proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}),
+ socket_control(Socket, Pid, Callback),
+ Ref = erlang:monitor(process, Pid),
+ handshake(Pid, Ref, Timeout)
+ catch
+ exit:{noproc, _} ->
+ {error, ssh_not_started};
+ _:Error ->
+ {error, Error}
+ end.
-%% Replaced with option to connection_info/3. For now keep
-%% for backwards compatibility
-peer_address(ConnectionHandler) ->
- sync_send_all_state_event(ConnectionHandler, peer_address).
+start_link(Role, Socket, Options) ->
+ {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Socket, Options]])}.
-%%====================================================================
-%% gen_fsm callbacks
-%%====================================================================
-%%--------------------------------------------------------------------
-%% Function: init(Args) -> {ok, StateName, State} |
-%% {ok, StateName, State, Timeout} |
-%% ignore |
-%% {stop, StopReason}
-%% Description:Whenever a gen_fsm is started using gen_fsm:start/[3,4] or
-%% gen_fsm:start_link/3,4, this function is called by the new process to
-%% initialize.
-%%--------------------------------------------------------------------
-init([Role, Manager, Socket, SshOpts]) ->
+init([Role, Socket, SshOpts]) ->
process_flag(trap_exit, true),
{NumVsn, StrVsn} = ssh_transport:versions(Role, SshOpts),
- ssh_bits:install_messages(ssh_transport:transport_messages(NumVsn)),
{Protocol, Callback, CloseTag} =
proplists:get_value(transport, SshOpts, {tcp, gen_tcp, tcp_closed}),
+ Cache = ssh_channel:cache_create(),
+ State0 = #state{
+ role = Role,
+ connection_state = #connection{channel_cache = Cache,
+ channel_id_seed = 0,
+ port_bindings = [],
+ requests = [],
+ options = SshOpts},
+ socket = Socket,
+ decoded_data_buffer = <<>>,
+ encoded_data_buffer = <<>>,
+ transport_protocol = Protocol,
+ transport_cb = Callback,
+ transport_close_tag = CloseTag,
+ opts = SshOpts
+ },
+
+ State = init_role(State0),
+
try init_ssh(Role, NumVsn, StrVsn, SshOpts, Socket) of
Ssh ->
- {ok, hello, #state{ssh_params =
- Ssh#ssh{send_sequence = 0, recv_sequence = 0},
- socket = Socket,
- decoded_data_buffer = <<>>,
- encoded_data_buffer = <<>>,
- transport_protocol = Protocol,
- transport_cb = Callback,
- transport_close_tag = CloseTag,
- manager = Manager,
- opts = SshOpts
- }}
+ gen_fsm:enter_loop(?MODULE, [], hello,
+ State#state{ssh_params = Ssh})
catch
- exit:Reason ->
- {stop, {shutdown, Reason}}
+ _:Error ->
+ gen_fsm:enter_loop(?MODULE, [], error, {Error, State0})
+ end.
+
+%%--------------------------------------------------------------------
+-spec open_channel(pid(), string(), iodata(), integer(), integer(),
+ timeout()) -> {open, channel_id()} | {open_error, term(), string(), string()}.
+%%--------------------------------------------------------------------
+open_channel(ConnectionHandler, ChannelType, ChannelSpecificData,
+ InitialWindowSize,
+ MaxPacketSize, Timeout) ->
+ sync_send_all_state_event(ConnectionHandler, {open, self(), ChannelType,
+ InitialWindowSize, MaxPacketSize,
+ ChannelSpecificData,
+ Timeout}).
+%%--------------------------------------------------------------------
+-spec request(pid(), pid(), channel_id(), string(), boolean(), iodata(),
+ timeout()) -> success | failure | ok | {error, term()}.
+%%--------------------------------------------------------------------
+request(ConnectionHandler, ChannelPid, ChannelId, Type, true, Data, Timeout) ->
+ sync_send_all_state_event(ConnectionHandler, {request, ChannelPid, ChannelId, Type, Data,
+ Timeout});
+request(ConnectionHandler, ChannelPid, ChannelId, Type, false, Data, _) ->
+ send_all_state_event(ConnectionHandler, {request, ChannelPid, ChannelId, Type, Data}).
+
+%%--------------------------------------------------------------------
+-spec request(pid(), channel_id(), string(), boolean(), iodata(),
+ timeout()) -> success | failure | {error, timeout}.
+%%--------------------------------------------------------------------
+request(ConnectionHandler, ChannelId, Type, true, Data, Timeout) ->
+ sync_send_all_state_event(ConnectionHandler, {request, ChannelId, Type, Data, Timeout});
+request(ConnectionHandler, ChannelId, Type, false, Data, _) ->
+ send_all_state_event(ConnectionHandler, {request, ChannelId, Type, Data}).
+
+%%--------------------------------------------------------------------
+-spec reply_request(pid(), success | failure, channel_id()) -> ok.
+%%--------------------------------------------------------------------
+reply_request(ConnectionHandler, Status, ChannelId) ->
+ send_all_state_event(ConnectionHandler, {reply_request, Status, ChannelId}).
+
+%%--------------------------------------------------------------------
+-spec global_request(pid(), string(), boolean(), iolist()) -> ok | error.
+%%--------------------------------------------------------------------
+global_request(ConnectionHandler, Type, true = Reply, Data) ->
+ case sync_send_all_state_event(ConnectionHandler,
+ {global_request, self(), Type, Reply, Data}) of
+ {ssh_cm, ConnectionHandler, {success, _}} ->
+ ok;
+ {ssh_cm, ConnectionHandler, {failure, _}} ->
+ error
+ end;
+global_request(ConnectionHandler, Type, false = Reply, Data) ->
+ send_all_state_event(ConnectionHandler, {global_request, self(), Type, Reply, Data}).
+
+%%--------------------------------------------------------------------
+-spec send(pid(), channel_id(), integer(), iolist(), timeout()) ->
+ ok | {error, timeout} | {error, closed}.
+%%--------------------------------------------------------------------
+send(ConnectionHandler, ChannelId, Type, Data, Timeout) ->
+ sync_send_all_state_event(ConnectionHandler, {data, ChannelId, Type, Data, Timeout}).
+
+%%--------------------------------------------------------------------
+-spec send_eof(pid(), channel_id()) -> ok | {error, closed}.
+%%--------------------------------------------------------------------
+send_eof(ConnectionHandler, ChannelId) ->
+ sync_send_all_state_event(ConnectionHandler, {eof, ChannelId}).
+
+%%--------------------------------------------------------------------
+-spec connection_info(pid(), [atom()]) -> proplists:proplist().
+%%--------------------------------------------------------------------
+connection_info(ConnectionHandler, Options) ->
+ sync_send_all_state_event(ConnectionHandler, {connection_info, Options}).
+
+%%--------------------------------------------------------------------
+-spec channel_info(pid(), channel_id(), [atom()]) -> proplists:proplist().
+%%--------------------------------------------------------------------
+channel_info(ConnectionHandler, ChannelId, Options) ->
+ sync_send_all_state_event(ConnectionHandler, {channel_info, ChannelId, Options}).
+
+%%--------------------------------------------------------------------
+-spec adjust_window(pid(), channel_id(), integer()) -> ok.
+%%--------------------------------------------------------------------
+adjust_window(ConnectionHandler, Channel, Bytes) ->
+ send_all_state_event(ConnectionHandler, {adjust_window, Channel, Bytes}).
+%%--------------------------------------------------------------------
+-spec renegotiate(pid()) -> ok.
+%%--------------------------------------------------------------------
+renegotiate(ConnectionHandler) ->
+ send_all_state_event(ConnectionHandler, renegotiate).
+
+%%--------------------------------------------------------------------
+-spec renegotiate_data(pid()) -> ok.
+%%--------------------------------------------------------------------
+renegotiate_data(ConnectionHandler) ->
+ send_all_state_event(ConnectionHandler, data_size).
+
+%%--------------------------------------------------------------------
+-spec close(pid(), channel_id()) -> ok.
+%%--------------------------------------------------------------------
+close(ConnectionHandler, ChannelId) ->
+ sync_send_all_state_event(ConnectionHandler, {close, ChannelId}).
+
+%%--------------------------------------------------------------------
+-spec stop(pid()) -> ok | {error, term()}.
+%%--------------------------------------------------------------------
+stop(ConnectionHandler)->
+ case sync_send_all_state_event(ConnectionHandler, stop) of
+ {error, closed} ->
+ ok;
+ Other ->
+ Other
end.
+
+info(ConnectionHandler) ->
+ info(ConnectionHandler, {info, all}).
+
+info(ConnectionHandler, ChannelProcess) ->
+ sync_send_all_state_event(ConnectionHandler, {info, ChannelProcess}).
+
+
+%%====================================================================
+%% gen_fsm callbacks
+%%====================================================================
+
%%--------------------------------------------------------------------
-%% Function:
-%% state_name(Event, State) -> {next_state, NextStateName, NextState}|
-%% {next_state, NextStateName,
-%% NextState, Timeout} |
-%% {stop, Reason, NewState}
-%% Description:There should be one instance of this function for each possible
-%% state name. Whenever a gen_fsm receives an event sent using
-%% gen_fsm:send_event/2, the instance of this function with the same name as
-%% the current state name StateName is called to handle the event. It is also
-%% called if a timeout occurs.
+-spec hello(socket_control | {info_line, list()} | {version_exchange, list()},
+ #state{}) -> gen_fsm_state_return().
%%--------------------------------------------------------------------
+
hello(socket_control, #state{socket = Socket, ssh_params = Ssh} = State) ->
VsnMsg = ssh_transport:hello_version_msg(string_version(Ssh)),
send_msg(VsnMsg, State),
- inet:setopts(Socket, [{packet, line}]),
- {next_state, hello, next_packet(State)};
+ inet:setopts(Socket, [{packet, line}, {active, once}]),
+ {next_state, hello, State};
-hello({info_line, _Line}, State) ->
- {next_state, hello, next_packet(State)};
+hello({info_line, _Line},#state{socket = Socket} = State) ->
+ inet:setopts(Socket, [{active, once}]),
+ {next_state, hello, State};
hello({version_exchange, Version}, #state{ssh_params = Ssh0,
socket = Socket} = State) ->
{NumVsn, StrVsn} = ssh_transport:handle_hello_version(Version),
case handle_version(NumVsn, StrVsn, Ssh0) of
{ok, Ssh1} ->
- inet:setopts(Socket, [{packet,0}, {mode,binary}]),
+ inet:setopts(Socket, [{packet,0}, {mode,binary}, {active, once}]),
{KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh1),
send_msg(SshPacket, State),
{next_state, kexinit, next_packet(State#state{ssh_params = Ssh,
@@ -173,12 +311,15 @@ hello({version_exchange, Version}, #state{ssh_params = Ssh0,
handle_disconnect(DisconnectMsg, State)
end.
+%%--------------------------------------------------------------------
+-spec kexinit({#ssh_msg_kexinit{}, binary()}, #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
kexinit({#ssh_msg_kexinit{} = Kex, Payload},
#state{ssh_params = #ssh{role = Role} = Ssh0,
- key_exchange_init_msg = OwnKex} =
- State) ->
+ key_exchange_init_msg = OwnKex} =
+ State) ->
Ssh1 = ssh_transport:key_init(opposite_role(Role), Ssh0, Payload),
- try ssh_transport:handle_kexinit_msg(Kex, OwnKex, Ssh1) of
+ case ssh_transport:handle_kexinit_msg(Kex, OwnKex, Ssh1) of
{ok, NextKexMsg, Ssh} when Role == client ->
send_msg(NextKexMsg, State),
{next_state, key_exchange,
@@ -186,157 +327,75 @@ kexinit({#ssh_msg_kexinit{} = Kex, Payload},
{ok, Ssh} when Role == server ->
{next_state, key_exchange,
next_packet(State#state{ssh_params = Ssh})}
- catch
- #ssh_msg_disconnect{} = DisconnectMsg ->
- handle_disconnect(DisconnectMsg, State);
- _:Error ->
- Desc = log_error(Error),
- handle_disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = Desc,
- language = "en"}, State)
end.
-
+
+%%--------------------------------------------------------------------
+-spec key_exchange(#ssh_msg_kexdh_init{} | #ssh_msg_kexdh_reply{} |
+ #ssh_msg_kex_dh_gex_group{} | #ssh_msg_kex_dh_gex_request{} |
+ #ssh_msg_kex_dh_gex_request{} | #ssh_msg_kex_dh_gex_reply{}, #state{})
+ -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
+
key_exchange(#ssh_msg_kexdh_init{} = Msg,
- #state{ssh_params = #ssh{role = server} =Ssh0} = State) ->
- try ssh_transport:handle_kexdh_init(Msg, Ssh0) of
+ #state{ssh_params = #ssh{role = server} = Ssh0} = State) ->
+ case ssh_transport:handle_kexdh_init(Msg, Ssh0) of
{ok, KexdhReply, Ssh1} ->
send_msg(KexdhReply, State),
{ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
send_msg(NewKeys, State),
{next_state, new_keys, next_packet(State#state{ssh_params = Ssh})}
- catch
- #ssh_msg_disconnect{} = DisconnectMsg ->
- handle_disconnect(DisconnectMsg, State);
- _:Error ->
- Desc = log_error(Error),
- handle_disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = Desc,
- language = "en"}, State)
end;
-key_exchange({#ssh_msg_kexinit{} = Kex, Payload},
- #state{ssh_params = #ssh{role = Role} = Ssh0,
- key_exchange_init_msg = OwnKex} =
- State) ->
- Ssh1 = ssh_transport:key_init(opposite_role(Role), Ssh0, Payload),
- try ssh_transport:handle_kexinit_msg(Kex, OwnKex, Ssh1) of
- {ok, NextKexMsg, Ssh} when Role == client ->
- send_msg(NextKexMsg, State),
- {next_state, key_exchange,
- next_packet(State#state{ssh_params = Ssh})};
- {ok, Ssh} when Role == server ->
- {next_state, key_exchange,
- next_packet(State#state{ssh_params = Ssh})}
- catch
- #ssh_msg_disconnect{} = DisconnectMsg ->
- handle_disconnect(DisconnectMsg, State);
- _:Error ->
- Desc = log_error(Error),
- handle_disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = Desc,
- language = "en"}, State)
- end;
-
key_exchange(#ssh_msg_kexdh_reply{} = Msg,
#state{ssh_params = #ssh{role = client} = Ssh0} = State) ->
- try ssh_transport:handle_kexdh_reply(Msg, Ssh0) of
- {ok, NewKeys, Ssh} ->
- send_msg(NewKeys, State),
- {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})}
- catch
- #ssh_msg_disconnect{} = DisconnectMsg ->
- handle_disconnect(DisconnectMsg, State);
- {ErrorToDisplay, #ssh_msg_disconnect{} = DisconnectMsg} ->
- handle_disconnect(DisconnectMsg, State, ErrorToDisplay);
- _:Error ->
- Desc = log_error(Error),
- handle_disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = Desc,
- language = "en"}, State)
- end;
+ {ok, NewKeys, Ssh} = ssh_transport:handle_kexdh_reply(Msg, Ssh0),
+ send_msg(NewKeys, State),
+ {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})};
key_exchange(#ssh_msg_kex_dh_gex_group{} = Msg,
#state{ssh_params = #ssh{role = server} = Ssh0} = State) ->
- try ssh_transport:handle_kex_dh_gex_group(Msg, Ssh0) of
- {ok, NextKexMsg, Ssh1} ->
- send_msg(NextKexMsg, State),
- {ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
- send_msg(NewKeys, State),
- {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})}
- catch
- #ssh_msg_disconnect{} = DisconnectMsg ->
- handle_disconnect(DisconnectMsg, State);
- _:Error ->
- Desc = log_error(Error),
- handle_disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = Desc,
- language = "en"}, State)
- end;
+ {ok, NextKexMsg, Ssh1} = ssh_transport:handle_kex_dh_gex_group(Msg, Ssh0),
+ send_msg(NextKexMsg, State),
+ {ok, NewKeys, Ssh} = ssh_transport:new_keys_message(Ssh1),
+ send_msg(NewKeys, State),
+ {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})};
key_exchange(#ssh_msg_kex_dh_gex_request{} = Msg,
#state{ssh_params = #ssh{role = client} = Ssh0} = State) ->
- try ssh_transport:handle_kex_dh_gex_request(Msg, Ssh0) of
- {ok, NextKexMsg, Ssh} ->
- send_msg(NextKexMsg, State),
- {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})}
- catch
- #ssh_msg_disconnect{} = DisconnectMsg ->
- handle_disconnect(DisconnectMsg, State);
- _:Error ->
- Desc = log_error(Error),
- handle_disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = Desc,
- language = "en"}, State)
- end;
+ {ok, NextKexMsg, Ssh} = ssh_transport:handle_kex_dh_gex_request(Msg, Ssh0),
+ send_msg(NextKexMsg, State),
+ {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})};
+
key_exchange(#ssh_msg_kex_dh_gex_reply{} = Msg,
#state{ssh_params = #ssh{role = client} = Ssh0} = State) ->
- try ssh_transport:handle_kex_dh_gex_reply(Msg, Ssh0) of
- {ok, NewKeys, Ssh} ->
- send_msg(NewKeys, State),
- {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})}
- catch
- #ssh_msg_disconnect{} = DisconnectMsg ->
- handle_disconnect(DisconnectMsg, State);
- _:Error ->
- Desc = log_error(Error),
- handle_disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = Desc,
- language = "en"}, State)
- end.
+ {ok, NewKeys, Ssh} = ssh_transport:handle_kex_dh_gex_reply(Msg, Ssh0),
+ send_msg(NewKeys, State),
+ {next_state, new_keys, next_packet(State#state{ssh_params = Ssh})}.
+
+%%--------------------------------------------------------------------
+-spec new_keys(#ssh_msg_newkeys{}, #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
new_keys(#ssh_msg_newkeys{} = Msg, #state{ssh_params = Ssh0} = State0) ->
- try ssh_transport:handle_new_keys(Msg, Ssh0) of
- {ok, Ssh} ->
- {NextStateName, State} =
- after_new_keys(State0#state{ssh_params = Ssh}),
- {next_state, NextStateName, next_packet(State)}
- catch
- #ssh_msg_disconnect{} = DisconnectMsg ->
- handle_disconnect(DisconnectMsg, State0);
- _:Error ->
- Desc = log_error(Error),
- handle_disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED,
- description = Desc,
- language = "en"}, State0)
- end.
+ {ok, Ssh} = ssh_transport:handle_new_keys(Msg, Ssh0),
+ {NextStateName, State} =
+ after_new_keys(State0#state{ssh_params = Ssh}),
+ {next_state, NextStateName, next_packet(State)}.
+
+%%--------------------------------------------------------------------
+-spec userauth(#ssh_msg_service_request{} | #ssh_msg_service_accept{} |
+ #ssh_msg_userauth_request{} | #ssh_msg_userauth_info_request{} |
+ #ssh_msg_userauth_info_response{} | #ssh_msg_userauth_success{} |
+ #ssh_msg_userauth_failure{} | #ssh_msg_userauth_banner{},
+ #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
userauth(#ssh_msg_service_request{name = "ssh-userauth"} = Msg,
#state{ssh_params = #ssh{role = server,
session_id = SessionId} = Ssh0} = State) ->
- ssh_bits:install_messages(ssh_auth:userauth_messages()),
- try ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0) of
- {ok, {Reply, Ssh}} ->
- send_msg(Reply, State),
- {next_state, userauth, next_packet(State#state{ssh_params = Ssh})}
- catch
- #ssh_msg_disconnect{} = DisconnectMsg ->
- handle_disconnect(DisconnectMsg, State);
- _:Error ->
- Desc = log_error(Error),
- handle_disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = Desc,
- language = "en"}, State)
- end;
+ {ok, {Reply, Ssh}} = ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0),
+ send_msg(Reply, State),
+ {next_state, userauth, next_packet(State#state{ssh_params = Ssh})};
userauth(#ssh_msg_service_accept{name = "ssh-userauth"},
#state{ssh_params = #ssh{role = client,
@@ -344,93 +403,55 @@ userauth(#ssh_msg_service_accept{name = "ssh-userauth"},
State) ->
{Msg, Ssh} = ssh_auth:init_userauth_request_msg(Ssh0),
send_msg(Msg, State),
- {next_state, userauth, next_packet(State#state{ssh_params = Ssh})};
+ {next_state, userauth, next_packet(State#state{auth_user = Ssh#ssh.user, ssh_params = Ssh})};
userauth(#ssh_msg_userauth_request{service = "ssh-connection",
method = "none"} = Msg,
#state{ssh_params = #ssh{session_id = SessionId, role = server,
service = "ssh-connection"} = Ssh0
} = State) ->
- try ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0) of
- {not_authorized, {_User, _Reason}, {Reply, Ssh}} ->
- send_msg(Reply, State),
- {next_state, userauth, next_packet(State#state{ssh_params = Ssh})}
- catch
- #ssh_msg_disconnect{} = DisconnectMsg ->
- handle_disconnect(DisconnectMsg, State);
- _:Error ->
- Desc = log_error(Error),
- handle_disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = Desc,
- language = "en"}, State)
- end;
+ {not_authorized, {_User, _Reason}, {Reply, Ssh}} =
+ ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0),
+ send_msg(Reply, State),
+ {next_state, userauth, next_packet(State#state{ssh_params = Ssh})};
userauth(#ssh_msg_userauth_request{service = "ssh-connection",
method = Method} = Msg,
#state{ssh_params = #ssh{session_id = SessionId, role = server,
service = "ssh-connection",
peer = {_, Address}} = Ssh0,
- opts = Opts, manager = Pid} = State) ->
- try ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0) of
+ opts = Opts, starter = Pid} = State) ->
+ case ssh_auth:handle_userauth_request(Msg, SessionId, Ssh0) of
{authorized, User, {Reply, Ssh}} ->
send_msg(Reply, State),
- ssh_userreg:register_user(User, Pid),
Pid ! ssh_connected,
connected_fun(User, Address, Method, Opts),
{next_state, connected,
- next_packet(State#state{ssh_params = Ssh})};
+ next_packet(State#state{auth_user = User, ssh_params = Ssh})};
{not_authorized, {User, Reason}, {Reply, Ssh}} ->
- retry_fun(User, Reason, Opts),
+ retry_fun(User, Address, Reason, Opts),
send_msg(Reply, State),
{next_state, userauth, next_packet(State#state{ssh_params = Ssh})}
- catch
- #ssh_msg_disconnect{} = DisconnectMsg ->
- handle_disconnect(DisconnectMsg, State);
- _:Error ->
- Desc = log_error(Error),
- handle_disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = Desc,
- language = "en"}, State)
end;
userauth(#ssh_msg_userauth_info_request{} = Msg,
#state{ssh_params = #ssh{role = client,
io_cb = IoCb} = Ssh0} = State) ->
- try ssh_auth:handle_userauth_info_request(Msg, IoCb, Ssh0) of
- {ok, {Reply, Ssh}} ->
- send_msg(Reply, State),
- {next_state, userauth, next_packet(State#state{ssh_params = Ssh})}
- catch
- #ssh_msg_disconnect{} = DisconnectMsg ->
- handle_disconnect(DisconnectMsg, State);
- _:Error ->
- Desc = log_error(Error),
- handle_disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = Desc,
- language = "en"}, State)
- end;
+ {ok, {Reply, Ssh}} = ssh_auth:handle_userauth_info_request(Msg, IoCb, Ssh0),
+ send_msg(Reply, State),
+ {next_state, userauth, next_packet(State#state{ssh_params = Ssh})};
userauth(#ssh_msg_userauth_info_response{} = Msg,
#state{ssh_params = #ssh{role = server} = Ssh0} = State) ->
- try ssh_auth:handle_userauth_info_response(Msg, Ssh0) of
- {ok, {Reply, Ssh}} ->
- send_msg(Reply, State),
- {next_state, userauth, next_packet(State#state{ssh_params = Ssh})}
- catch
- #ssh_msg_disconnect{} = DisconnectMsg ->
- handle_disconnect(DisconnectMsg, State);
- _:Error ->
- Desc = log_error(Error),
- handle_disconnect(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
- description = Desc,
- language = "en"}, State)
- end;
+ {ok, {Reply, Ssh}} = ssh_auth:handle_userauth_info_response(Msg, Ssh0),
+ send_msg(Reply, State),
+ {next_state, userauth, next_packet(State#state{ssh_params = Ssh})};
userauth(#ssh_msg_userauth_success{}, #state{ssh_params = #ssh{role = client} = Ssh,
- manager = Pid} = State) ->
+ starter = Pid} = State) ->
Pid ! ssh_connected,
- {next_state, connected, next_packet(State#state{ssh_params = Ssh#ssh{authenticated = true}})};
-
+ {next_state, connected, next_packet(State#state{ssh_params =
+ Ssh#ssh{authenticated = true}})};
userauth(#ssh_msg_userauth_failure{},
#state{ssh_params = #ssh{role = client,
userauth_methods = []}}
@@ -479,31 +500,27 @@ userauth(#ssh_msg_userauth_banner{message = Msg},
io:format("~s", [Msg]),
{next_state, userauth, next_packet(State)}.
+%%--------------------------------------------------------------------
+-spec connected({#ssh_msg_kexinit{}, binary()}, %%| %% #ssh_msg_kexdh_init{},
+ #state{}) -> gen_fsm_state_return().
+%%--------------------------------------------------------------------
connected({#ssh_msg_kexinit{}, _Payload} = Event, State) ->
- kexinit(Event, State#state{renegotiate = true});
-connected({#ssh_msg_kexdh_init{}, _Payload} = Event, State) ->
- key_exchange(Event, State#state{renegotiate = true}).
+ kexinit(Event, State#state{renegotiate = true}).
+%% ;
+%% connected(#ssh_msg_kexdh_init{} = Event, State) ->
+%% key_exchange(Event, State#state{renegotiate = true}).
%%--------------------------------------------------------------------
-%% Function:
-%% handle_event(Event, StateName, State) -> {next_state, NextStateName,
-%% NextState} |
-%% {next_state, NextStateName,
-%% NextState, Timeout} |
-%% {stop, Reason, NewState}
-%% Description: Whenever a gen_fsm receives an event sent using
-%% gen_fsm:send_all_state_event/2, this function is called to handle
-%% the event.
-%%--------------------------------------------------------------------
-handle_event({send, Data}, StateName, #state{ssh_params = Ssh0} = State) ->
- {Packet, Ssh} = ssh_transport:pack(Data, Ssh0),
- send_msg(Packet, State),
- {next_state, StateName, next_packet(State#state{ssh_params = Ssh})};
+-spec handle_event(#ssh_msg_disconnect{} | #ssh_msg_ignore{} | #ssh_msg_debug{} |
+ #ssh_msg_unimplemented{} | {adjust_window, integer(), integer()} |
+ {reply_request, success | failure, integer()} | renegotiate |
+ data_size | {request, pid(), integer(), integer(), iolist()} |
+ {request, integer(), integer(), iolist()}, state_name(),
+ #state{}) -> gen_fsm_state_return().
-handle_event(#ssh_msg_disconnect{} = Msg, _StateName,
- #state{manager = Pid} = State) ->
- (catch ssh_connection_manager:event(Pid, Msg)),
- {stop, normal, State};
+%%--------------------------------------------------------------------
+handle_event(#ssh_msg_disconnect{description = Desc}, _StateName, #state{} = State) ->
+ {stop, {shutdown, Desc}, State};
handle_event(#ssh_msg_ignore{}, StateName, State) ->
{next_state, StateName, next_packet(State)};
@@ -519,30 +536,58 @@ handle_event(#ssh_msg_debug{}, StateName, State) ->
handle_event(#ssh_msg_unimplemented{}, StateName, State) ->
{next_state, StateName, next_packet(State)};
+handle_event({adjust_window, ChannelId, Bytes}, StateName,
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State0) ->
+ State =
+ case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{recv_window_size = WinSize, remote_id = Id} = Channel ->
+ ssh_channel:cache_update(Cache, Channel#channel{recv_window_size =
+ WinSize + Bytes}),
+ Msg = ssh_connection:channel_adjust_window_msg(Id, Bytes),
+ send_replies([{connection_reply, Msg}], State0);
+ undefined ->
+ State0
+ end,
+ {next_state, StateName, next_packet(State)};
+
+handle_event({reply_request, success, ChannelId}, StateName,
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State0) ->
+ State = case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{remote_id = RemoteId} ->
+ Msg = ssh_connection:channel_success_msg(RemoteId),
+ send_replies([{connection_reply, Msg}], State0);
+ undefined ->
+ State0
+ end,
+ {next_state, StateName, State};
+
handle_event(renegotiate, connected, #state{ssh_params = Ssh0}
= State) ->
{KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh0),
send_msg(SshPacket, State),
- {next_state, connected,
+ timer:apply_after(?REKEY_TIMOUT, gen_fsm, send_all_state_event, [self(), renegotiate]),
+ {next_state, kexinit,
next_packet(State#state{ssh_params = Ssh,
key_exchange_init_msg = KeyInitMsg,
renegotiate = true})};
handle_event(renegotiate, StateName, State) ->
+ timer:apply_after(?REKEY_TIMOUT, gen_fsm, send_all_state_event, [self(), renegotiatie]),
%% Allready in keyexcahange so ignore
{next_state, StateName, State};
-handle_event({info, From, Options}, StateName, #state{ssh_params = Ssh} = State) ->
- spawn(?MODULE, ssh_info_handler, [Options, Ssh, From]),
- {next_state, StateName, State};
+%% Rekey due to sent data limit reached?
handle_event(data_size, connected, #state{ssh_params = Ssh0} = State) ->
{ok, [{send_oct,Sent}]} = inet:getstat(State#state.socket, [send_oct]),
MaxSent = proplists:get_value(rekey_limit, State#state.opts, 1024000000),
+ timer:apply_after(?REKEY_DATA_TIMOUT, gen_fsm, send_all_state_event, [self(), data_size]),
case Sent >= MaxSent of
true ->
{KeyInitMsg, SshPacket, Ssh} = ssh_transport:key_exchange_init_msg(Ssh0),
send_msg(SshPacket, State),
- {next_state, connected,
+ {next_state, kexinit,
next_packet(State#state{ssh_params = Ssh,
key_exchange_init_msg = KeyInitMsg,
renegotiate = true})};
@@ -551,42 +596,196 @@ handle_event(data_size, connected, #state{ssh_params = Ssh0} = State) ->
end;
handle_event(data_size, StateName, State) ->
{next_state, StateName, State};
+
+handle_event({request, ChannelPid, ChannelId, Type, Data}, StateName, State0) ->
+ {{replies, Replies}, State1} = handle_request(ChannelPid, ChannelId,
+ Type, Data,
+ false, none, State0),
+ State = send_replies(Replies, State1),
+ {next_state, StateName, next_packet(State)};
+
+handle_event({request, ChannelId, Type, Data}, StateName, State0) ->
+ {{replies, Replies}, State1} = handle_request(ChannelId, Type, Data,
+ false, none, State0),
+ State = send_replies(Replies, State1),
+ {next_state, StateName, next_packet(State)};
+
handle_event({unknown, Data}, StateName, State) ->
Msg = #ssh_msg_unimplemented{sequence = Data},
send_msg(Msg, State),
{next_state, StateName, next_packet(State)}.
+
%%--------------------------------------------------------------------
-%% Function:
-%% handle_sync_event(Event, From, StateName,
-%% State) -> {next_state, NextStateName, NextState} |
-%% {next_state, NextStateName, NextState,
-%% Timeout} |
-%% {reply, Reply, NextStateName, NextState}|
-%% {reply, Reply, NextStateName, NextState,
-%% Timeout} |
-%% {stop, Reason, NewState} |
-%% {stop, Reason, Reply, NewState}
-%% Description: Whenever a gen_fsm receives an event sent using
-%% gen_fsm:sync_send_all_state_event/2,3, this function is called to handle
-%% the event.
+-spec handle_sync_event({request, pid(), channel_id(), integer(), binary(), timeout()} |
+ {request, channel_id(), integer(), binary(), timeout()} |
+ {global_request, pid(), integer(), boolean(), binary()} | {eof, integer()} |
+ {open, pid(), integer(), channel_id(), integer(), binary(), _} |
+ {send_window, channel_id()} | {recv_window, channel_id()} |
+ {connection_info, [client_version | server_version | peer |
+ sockname]} | {channel_info, channel_id(), [recv_window |
+ send_window]} |
+ {close, channel_id()} | stop, term(), state_name(), #state{})
+ -> gen_fsm_state_return().
%%--------------------------------------------------------------------
+handle_sync_event({request, ChannelPid, ChannelId, Type, Data, Timeout}, From, StateName, State0) ->
+ {{replies, Replies}, State1} = handle_request(ChannelPid,
+ ChannelId, Type, Data,
+ true, From, State0),
+ %% Note reply to channel will happen later when
+ %% reply is recived from peer on the socket
+ State = send_replies(Replies, State1),
+ start_timeout(ChannelId, From, Timeout),
+ handle_idle_timeout(State),
+ {next_state, StateName, next_packet(State)};
+
+handle_sync_event({request, ChannelId, Type, Data, Timeout}, From, StateName, State0) ->
+ {{replies, Replies}, State1} = handle_request(ChannelId, Type, Data,
+ true, From, State0),
+ %% Note reply to channel will happen later when
+ %% reply is recived from peer on the socket
+ State = send_replies(Replies, State1),
+ start_timeout(ChannelId, From, Timeout),
+ handle_idle_timeout(State),
+ {next_state, StateName, next_packet(State)};
+
+handle_sync_event({global_request, Pid, _, _, _} = Request, From, StateName,
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State0) ->
+ State1 = handle_global_request(Request, State0),
+ Channel = ssh_channel:cache_find(Pid, Cache),
+ State = add_request(true, Channel#channel.local_id, From, State1),
+ {next_state, StateName, next_packet(State)};
-%% Replaced with option to connection_info/3. For now keep
-%% for backwards compatibility
-handle_sync_event(peer_address, _From, StateName,
- #state{ssh_params = #ssh{peer = {_, Address}}} = State) ->
- {reply, {ok, Address}, StateName, State}.
+handle_sync_event({data, ChannelId, Type, Data, Timeout}, From, StateName,
+ #state{connection_state = #connection{channel_cache = _Cache}
+ = Connection0} = State0) ->
+
+ case ssh_connection:channel_data(ChannelId, Type, Data, Connection0, From) of
+ {{replies, Replies}, Connection} ->
+ State = send_replies(Replies, State0#state{connection_state = Connection}),
+ start_timeout(ChannelId, From, Timeout),
+ {next_state, StateName, next_packet(State)};
+ {noreply, Connection} ->
+ start_timeout(ChannelId, From, Timeout),
+ {next_state, StateName, next_packet(State0#state{connection_state = Connection})}
+ end;
+
+handle_sync_event({eof, ChannelId}, _From, StateName,
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State0) ->
+ case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{remote_id = Id, sent_close = false} ->
+ State = send_replies([{connection_reply,
+ ssh_connection:channel_eof_msg(Id)}], State0),
+ {reply, ok, StateName, next_packet(State)};
+ _ ->
+ {reply, {error,closed}, StateName, State0}
+ end;
+
+handle_sync_event({open, ChannelPid, Type, InitialWindowSize, MaxPacketSize, Data, Timeout},
+ From, StateName, #state{connection_state =
+ #connection{channel_cache = Cache}} = State0) ->
+ erlang:monitor(process, ChannelPid),
+ {ChannelId, State1} = new_channel_id(State0),
+ Msg = ssh_connection:channel_open_msg(Type, ChannelId,
+ InitialWindowSize,
+ MaxPacketSize, Data),
+ State2 = send_replies([{connection_reply, Msg}], State1),
+ Channel = #channel{type = Type,
+ sys = "none",
+ user = ChannelPid,
+ local_id = ChannelId,
+ recv_window_size = InitialWindowSize,
+ recv_packet_size = MaxPacketSize},
+ ssh_channel:cache_update(Cache, Channel),
+ State = add_request(true, ChannelId, From, State2),
+ start_timeout(ChannelId, From, Timeout),
+ {next_state, StateName, next_packet(remove_timer_ref(State))};
+
+handle_sync_event({send_window, ChannelId}, _From, StateName,
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State) ->
+ Reply = case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{send_window_size = WinSize,
+ send_packet_size = Packsize} ->
+ {ok, {WinSize, Packsize}};
+ undefined ->
+ {error, einval}
+ end,
+ {reply, Reply, StateName, next_packet(State)};
+
+handle_sync_event({recv_window, ChannelId}, _From, StateName,
+ #state{connection_state = #connection{channel_cache = Cache}}
+ = State) ->
+
+ Reply = case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{recv_window_size = WinSize,
+ recv_packet_size = Packsize} ->
+ {ok, {WinSize, Packsize}};
+ undefined ->
+ {error, einval}
+ end,
+ {reply, Reply, StateName, next_packet(State)};
+
+handle_sync_event({connection_info, Options}, _From, StateName, State) ->
+ Info = ssh_info(Options, State, []),
+ {reply, Info, StateName, State};
+
+handle_sync_event({channel_info, ChannelId, Options}, _From, StateName,
+ #state{connection_state = #connection{channel_cache = Cache}} = State) ->
+ case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{} = Channel ->
+ Info = ssh_channel_info(Options, Channel, []),
+ {reply, Info, StateName, State};
+ undefined ->
+ {reply, [], StateName, State}
+ end;
+
+handle_sync_event({info, ChannelPid}, _From, StateName,
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State) ->
+ Result = ssh_channel:cache_foldl(
+ fun(Channel, Acc) when ChannelPid == all;
+ Channel#channel.user == ChannelPid ->
+ [Channel | Acc];
+ (_, Acc) ->
+ Acc
+ end, [], Cache),
+ {reply, {ok, Result}, StateName, State};
+
+handle_sync_event({close, ChannelId}, _, StateName,
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State0) ->
+ State =
+ case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{remote_id = Id} = Channel ->
+ State1 = send_replies([{connection_reply,
+ ssh_connection:channel_close_msg(Id)}], State0),
+ ssh_channel:cache_update(Cache, Channel#channel{sent_close = true}),
+ handle_idle_timeout(State1),
+ State1;
+ undefined ->
+ State0
+ end,
+ {reply, ok, StateName, next_packet(State)};
+
+handle_sync_event(stop, _, _StateName, #state{connection_state = Connection0,
+ role = Role,
+ opts = Opts} = State0) ->
+ {disconnect, Reason, {{replies, Replies}, Connection}} =
+ ssh_connection:handle_msg(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
+ description = "User closed down connection",
+ language = "en"}, Connection0, Role),
+ State = send_replies(Replies, State0),
+ SSHOpts = proplists:get_value(ssh_opts, Opts),
+ disconnect_fun(Reason, SSHOpts),
+ {stop, normal, ok, State#state{connection_state = Connection}}.
%%--------------------------------------------------------------------
-%% Function:
-%% handle_info(Info,StateName,State)-> {next_state, NextStateName, NextState}|
-%% {next_state, NextStateName, NextState,
-%% Timeout} |
-%% {stop, Reason, NewState}
-%% Description: This function is called by a gen_fsm when it receives any
-%% other message than a synchronous or asynchronous event
-%% (or a system message).
+-spec handle_info({atom(), port(), binary()} | {atom(), port()} |
+ term (), state_name(), #state{}) -> gen_fsm_state_return().
%%--------------------------------------------------------------------
+
handle_info({Protocol, Socket, "SSH-" ++ _ = Version}, hello,
#state{socket = Socket,
transport_protocol = Protocol} = State ) ->
@@ -651,15 +850,35 @@ handle_info({Protocol, Socket, Data}, Statename,
handle_info({CloseTag, _Socket}, _StateName,
#state{transport_close_tag = CloseTag,
ssh_params = #ssh{role = _Role, opts = _Opts}} = State) ->
- DisconnectMsg =
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_CONNECTION_LOST,
- description = "Connection Lost",
- language = "en"},
- {stop, {shutdown, DisconnectMsg}, State};
+ {stop, {shutdown, "Connection Lost"}, State};
+
+handle_info({timeout, {_, From} = Request}, Statename,
+ #state{connection_state = #connection{requests = Requests} = Connection} = State) ->
+ case lists:member(Request, Requests) of
+ true ->
+ gen_fsm:reply(From, {error, timeout}),
+ {next_state, Statename,
+ State#state{connection_state =
+ Connection#connection{requests =
+ lists:delete(Request, Requests)}}};
+ false ->
+ {next_state, Statename, State}
+ end;
+
+%%% Handle that ssh channels user process goes down
+handle_info({'DOWN', _Ref, process, ChannelPid, _Reason}, Statename, State0) ->
+ {{replies, Replies}, State1} = handle_channel_down(ChannelPid, State0),
+ State = send_replies(Replies, State1),
+ {next_state, Statename, next_packet(State)};
%%% So that terminate will be run when supervisor is shutdown
handle_info({'EXIT', _Sup, Reason}, _StateName, State) ->
- {stop, Reason, State};
+ {stop, {shutdown, Reason}, State};
+
+handle_info({check_cache, _ , _},
+ StateName, #state{connection_state =
+ #connection{channel_cache = Cache}} = State) ->
+ {next_state, StateName, check_cache(State, Cache)};
handle_info(UnexpectedMessage, StateName, #state{ssh_params = SshParams} = State) ->
Msg = lists:flatten(io_lib:format(
@@ -673,20 +892,16 @@ handle_info(UnexpectedMessage, StateName, #state{ssh_params = SshParams} = State
{next_state, StateName, State}.
%%--------------------------------------------------------------------
-%% Function: terminate(Reason, StateName, State) -> void()
-%% Description:This function is called by a gen_fsm when it is about
-%% to terminate. It should be the opposite of Module:init/1 and do any
-%% necessary cleaning up. When it returns, the gen_fsm terminates with
-%% Reason. The return value is ignored.
+-spec terminate(Reason::term(), state_name(), #state{}) -> _.
%%--------------------------------------------------------------------
terminate(normal, _, #state{transport_cb = Transport,
- socket = Socket,
- manager = Pid}) ->
- (catch ssh_userreg:delete_user(Pid)),
+ connection_state = Connection,
+ socket = Socket}) ->
+ terminate_subsytem(Connection),
(catch Transport:close(Socket)),
ok;
-%% Terminated as manager terminated
+%% Terminated by supervisor
terminate(shutdown, StateName, #state{ssh_params = Ssh0} = State) ->
DisconnectMsg =
#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
@@ -696,31 +911,34 @@ terminate(shutdown, StateName, #state{ssh_params = Ssh0} = State) ->
send_msg(SshPacket, State),
terminate(normal, StateName, State#state{ssh_params = Ssh});
-terminate({shutdown, #ssh_msg_disconnect{} = Msg}, StateName, #state{ssh_params = Ssh0, manager = Pid} = State) ->
- {SshPacket, Ssh} = ssh_transport:ssh_packet(Msg, Ssh0),
- send_msg(SshPacket, State),
- ssh_connection_manager:event(Pid, Msg),
- terminate(normal, StateName, State#state{ssh_params = Ssh});
-terminate({shutdown, {#ssh_msg_disconnect{} = Msg, ErrorMsg}}, StateName, #state{ssh_params = Ssh0, manager = Pid} = State) ->
- {SshPacket, Ssh} = ssh_transport:ssh_packet(Msg, Ssh0),
+terminate({shutdown, #ssh_msg_disconnect{} = Msg}, StateName,
+ #state{ssh_params = Ssh0} = State) ->
+ {SshPacket, Ssh} = ssh_transport:ssh_packet(Msg, Ssh0),
send_msg(SshPacket, State),
- ssh_connection_manager:event(Pid, Msg, ErrorMsg),
- terminate(normal, StateName, State#state{ssh_params = Ssh});
-terminate(Reason, StateName, #state{ssh_params = Ssh0, manager = Pid} = State) ->
+ terminate(normal, StateName, State#state{ssh_params = Ssh});
+terminate({shutdown, _}, StateName, State) ->
+ terminate(normal, StateName, State);
+terminate(Reason, StateName, #state{ssh_params = Ssh0, starter = _Pid,
+ connection_state = Connection} = State) ->
+ terminate_subsytem(Connection),
log_error(Reason),
DisconnectMsg =
#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
description = "Internal error",
language = "en"},
{SshPacket, Ssh} = ssh_transport:ssh_packet(DisconnectMsg, Ssh0),
- ssh_connection_manager:event(Pid, DisconnectMsg),
send_msg(SshPacket, State),
terminate(normal, StateName, State#state{ssh_params = Ssh}).
+terminate_subsytem(#connection{system_supervisor = SysSup,
+ sub_system_supervisor = SubSysSup}) when is_pid(SubSysSup) ->
+ ssh_system_sup:stop_subsystem(SysSup, SubSysSup);
+terminate_subsytem(_) ->
+ ok.
+
%%--------------------------------------------------------------------
-%% Function:
-%% code_change(OldVsn, StateName, State, Extra) -> {ok, StateName, NewState}
-%% Description: Convert process state when code is changed
+-spec code_change(OldVsn::term(), state_name(), Oldstate::term(), Extra::term()) ->
+ {ok, state_name(), #state{}}.
%%--------------------------------------------------------------------
code_change(_OldVsn, StateName, State, _Extra) ->
{ok, StateName, State}.
@@ -728,6 +946,39 @@ code_change(_OldVsn, StateName, State, _Extra) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+init_role(#state{role = client, opts = Opts} = State0) ->
+ Pid = proplists:get_value(user_pid, Opts),
+ TimerRef = get_idle_time(Opts),
+ timer:apply_after(?REKEY_TIMOUT, gen_fsm, send_all_state_event, [self(), renegotiate]),
+ timer:apply_after(?REKEY_DATA_TIMOUT, gen_fsm, send_all_state_event,
+ [self(), data_size]),
+ State0#state{starter = Pid,
+ idle_timer_ref = TimerRef};
+init_role(#state{role = server, opts = Opts, connection_state = Connection} = State) ->
+ Sups = proplists:get_value(supervisors, Opts),
+ Pid = proplists:get_value(user_pid, Opts),
+ SystemSup = proplists:get_value(system_sup, Sups),
+ SubSystemSup = proplists:get_value(subsystem_sup, Sups),
+ ConnectionSup = proplists:get_value(connection_sup, Sups),
+ Shell = proplists:get_value(shell, Opts),
+ Exec = proplists:get_value(exec, Opts),
+ CliSpec = proplists:get_value(ssh_cli, Opts, {ssh_cli, [Shell]}),
+ State#state{starter = Pid, connection_state = Connection#connection{
+ cli_spec = CliSpec,
+ exec = Exec,
+ system_supervisor = SystemSup,
+ sub_system_supervisor = SubSystemSup,
+ connection_supervisor = ConnectionSup
+ }}.
+
+get_idle_time(SshOptions) ->
+ case proplists:get_value(idle_time, SshOptions) of
+ infinity ->
+ infinity;
+ _IdleTime -> %% We dont want to set the timeout on first connect
+ undefined
+ end.
+
init_ssh(client = Role, Vsn, Version, Options, Socket) ->
IOCb = case proplists:get_value(user_interaction, Options, true) of
true ->
@@ -845,7 +1096,15 @@ send_all_state_event(FsmPid, Event) ->
gen_fsm:send_all_state_event(FsmPid, Event).
sync_send_all_state_event(FsmPid, Event) ->
- gen_fsm:sync_send_all_state_event(FsmPid, Event).
+ try gen_fsm:sync_send_all_state_event(FsmPid, Event, infinity)
+ catch
+ exit:{noproc, _} ->
+ {error, closed};
+ exit:{normal, _} ->
+ {error, closed};
+ exit:{{shutdown, _},_} ->
+ {error, closed}
+ end.
%% simulate send_all_state_event(self(), Event)
event(#ssh_msg_disconnect{} = Event, StateName, State) ->
@@ -858,10 +1117,33 @@ event(#ssh_msg_unimplemented{} = Event, StateName, State) ->
handle_event(Event, StateName, State);
%% simulate send_event(self(), Event)
event(Event, StateName, State) ->
- ?MODULE:StateName(Event, State).
+ try
+ ?MODULE:StateName(Event, State)
+ catch
+ throw:#ssh_msg_disconnect{} = DisconnectMsg ->
+ handle_disconnect(DisconnectMsg, State);
+ throw:{ErrorToDisplay, #ssh_msg_disconnect{} = DisconnectMsg} ->
+ handle_disconnect(DisconnectMsg, State, ErrorToDisplay);
+ _:Error ->
+ log_error(Error),
+ handle_disconnect(#ssh_msg_disconnect{code = error_code(StateName),
+ description = "Internal error",
+ language = "en"}, State)
+ end.
+error_code(key_exchange) ->
+ ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED;
+error_code(new_keys) ->
+ ?SSH_DISCONNECT_KEY_EXCHANGE_FAILED;
+error_code(_) ->
+ ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE.
generate_event(<<?BYTE(Byte), _/binary>> = Msg, StateName,
- #state{manager = Pid} = State0, EncData)
+ #state{
+ role = Role,
+ starter = User,
+ opts = Opts,
+ renegotiate = Renegotiation,
+ connection_state = Connection0} = State0, EncData)
when Byte == ?SSH_MSG_GLOBAL_REQUEST;
Byte == ?SSH_MSG_REQUEST_SUCCESS;
Byte == ?SSH_MSG_REQUEST_FAILURE;
@@ -876,18 +1158,40 @@ generate_event(<<?BYTE(Byte), _/binary>> = Msg, StateName,
Byte == ?SSH_MSG_CHANNEL_REQUEST;
Byte == ?SSH_MSG_CHANNEL_SUCCESS;
Byte == ?SSH_MSG_CHANNEL_FAILURE ->
-
- try
- ssh_connection_manager:event(Pid, Msg),
- State = generate_event_new_state(State0, EncData),
- next_packet(State),
- {next_state, StateName, State}
+ ConnectionMsg = ssh_message:decode(Msg),
+ State1 = generate_event_new_state(State0, EncData),
+ try ssh_connection:handle_msg(ConnectionMsg, Connection0, Role) of
+ {{replies, Replies}, Connection} ->
+ State = send_replies(Replies, State1#state{connection_state = Connection}),
+ {next_state, StateName, next_packet(State)};
+ {noreply, Connection} ->
+ {next_state, StateName, next_packet(State1#state{connection_state = Connection})};
+ {disconnect, {_, Reason}, {{replies, Replies}, Connection}} when
+ Role == client andalso ((StateName =/= connected) and (not Renegotiation)) ->
+ State = send_replies(Replies, State1#state{connection_state = Connection}),
+ User ! {self(), not_connected, Reason},
+ {stop, {shutdown, normal},
+ next_packet(State#state{connection_state = Connection})};
+ {disconnect, Reason, {{replies, Replies}, Connection}} ->
+ State = send_replies(Replies, State1#state{connection_state = Connection}),
+ SSHOpts = proplists:get_value(ssh_opts, Opts),
+ disconnect_fun(Reason, SSHOpts),
+ {stop, {shutdown, normal}, State#state{connection_state = Connection}}
catch
- exit:{noproc, Reason} ->
- {stop, {shutdown, Reason}, State0}
+ _:Error ->
+ {disconnect, Reason, {{replies, Replies}, Connection}} =
+ ssh_connection:handle_msg(
+ #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
+ description = "Internal error",
+ language = "en"}, Connection0, Role),
+ State = send_replies(Replies, State1#state{connection_state = Connection}),
+ SSHOpts = proplists:get_value(ssh_opts, Opts),
+ disconnect_fun(Reason, SSHOpts),
+ {stop, {shutdown, Error}, State#state{connection_state = Connection}}
end;
+
generate_event(Msg, StateName, State0, EncData) ->
- Event = ssh_bits:decode(Msg),
+ Event = ssh_message:decode(Msg),
State = generate_event_new_state(State0, EncData),
case Event of
#ssh_msg_kexinit{} ->
@@ -897,6 +1201,100 @@ generate_event(Msg, StateName, State0, EncData) ->
event(Event, StateName, State)
end.
+
+handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From,
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State0) ->
+ case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{remote_id = Id} = Channel ->
+ update_sys(Cache, Channel, Type, ChannelPid),
+ Msg = ssh_connection:channel_request_msg(Id, Type,
+ WantReply, Data),
+ Replies = [{connection_reply, Msg}],
+ State = add_request(WantReply, ChannelId, From, State0),
+ {{replies, Replies}, State};
+ undefined ->
+ {{replies, []}, State0}
+ end.
+
+handle_request(ChannelId, Type, Data, WantReply, From,
+ #state{connection_state =
+ #connection{channel_cache = Cache}} = State0) ->
+ case ssh_channel:cache_lookup(Cache, ChannelId) of
+ #channel{remote_id = Id} ->
+ Msg = ssh_connection:channel_request_msg(Id, Type,
+ WantReply, Data),
+ Replies = [{connection_reply, Msg}],
+ State = add_request(WantReply, ChannelId, From, State0),
+ {{replies, Replies}, State};
+ undefined ->
+ {{replies, []}, State0}
+ end.
+
+handle_global_request({global_request, ChannelPid,
+ "tcpip-forward" = Type, WantReply,
+ <<?UINT32(IPLen),
+ IP:IPLen/binary, ?UINT32(Port)>> = Data},
+ #state{connection_state =
+ #connection{channel_cache = Cache}
+ = Connection0} = State) ->
+ ssh_channel:cache_update(Cache, #channel{user = ChannelPid,
+ type = "forwarded-tcpip",
+ sys = none}),
+ Connection = ssh_connection:bind(IP, Port, ChannelPid, Connection0),
+ Msg = ssh_connection:global_request_msg(Type, WantReply, Data),
+ send_replies([{connection_reply, Msg}], State#state{connection_state = Connection});
+
+handle_global_request({global_request, _Pid, "cancel-tcpip-forward" = Type,
+ WantReply, <<?UINT32(IPLen),
+ IP:IPLen/binary, ?UINT32(Port)>> = Data},
+ #state{connection_state = Connection0} = State) ->
+ Connection = ssh_connection:unbind(IP, Port, Connection0),
+ Msg = ssh_connection:global_request_msg(Type, WantReply, Data),
+ send_replies([{connection_reply, Msg}], State#state{connection_state = Connection});
+
+handle_global_request({global_request, _, "cancel-tcpip-forward" = Type,
+ WantReply, Data}, State) ->
+ Msg = ssh_connection:global_request_msg(Type, WantReply, Data),
+ send_replies([{connection_reply, Msg}], State).
+
+handle_idle_timeout(#state{opts = Opts}) ->
+ case proplists:get_value(idle_time, Opts, infinity) of
+ infinity ->
+ ok;
+ IdleTime ->
+ erlang:send_after(IdleTime, self(), {check_cache, [], []})
+ end.
+
+handle_channel_down(ChannelPid, #state{connection_state =
+ #connection{channel_cache = Cache}} =
+ State) ->
+ ssh_channel:cache_foldl(
+ fun(Channel, Acc) when Channel#channel.user == ChannelPid ->
+ ssh_channel:cache_delete(Cache,
+ Channel#channel.local_id),
+ Acc;
+ (_,Acc) ->
+ Acc
+ end, [], Cache),
+ {{replies, []}, check_cache(State, Cache)}.
+
+update_sys(Cache, Channel, Type, ChannelPid) ->
+ ssh_channel:cache_update(Cache,
+ Channel#channel{sys = Type, user = ChannelPid}).
+add_request(false, _ChannelId, _From, State) ->
+ State;
+add_request(true, ChannelId, From, #state{connection_state =
+ #connection{requests = Requests0} =
+ Connection} = State) ->
+ Requests = [{ChannelId, From} | Requests0],
+ State#state{connection_state = Connection#connection{requests = Requests}}.
+
+new_channel_id(#state{connection_state = #connection{channel_id_seed = Id} =
+ Connection}
+ = State) ->
+ {Id, State#state{connection_state =
+ Connection#connection{channel_id_seed = Id + 1}}}.
generate_event_new_state(#state{ssh_params =
#ssh{recv_sequence = SeqNum0}
= Ssh} = State, EncData) ->
@@ -906,7 +1304,6 @@ generate_event_new_state(#state{ssh_params =
encoded_data_buffer = EncData,
undecoded_packet_length = undefined}.
-
next_packet(#state{decoded_data_buffer = <<>>,
encoded_data_buffer = Buff,
ssh_params = #ssh{decrypt_block_size = BlockSize},
@@ -931,7 +1328,6 @@ after_new_keys(#state{renegotiate = true} = State) ->
{connected, State#state{renegotiate = false}};
after_new_keys(#state{renegotiate = false,
ssh_params = #ssh{role = client} = Ssh0} = State) ->
- ssh_bits:install_messages(ssh_auth:userauth_messages()),
{Msg, Ssh} = ssh_auth:service_request_msg(Ssh0),
send_msg(Msg, State),
{userauth, State#state{ssh_params = Ssh}};
@@ -981,10 +1377,10 @@ handle_ssh_packet(Length, StateName, #state{decoded_data_buffer = DecData0,
handle_disconnect(DisconnectMsg, State0)
end.
-handle_disconnect(#ssh_msg_disconnect{} = Msg, State) ->
- {stop, {shutdown, Msg}, State}.
-handle_disconnect(#ssh_msg_disconnect{} = Msg, State, ErrorMsg) ->
- {stop, {shutdown, {Msg, ErrorMsg}}, State}.
+handle_disconnect(#ssh_msg_disconnect{description = Desc}, State) ->
+ {stop, {shutdown, Desc}, State}.
+handle_disconnect(#ssh_msg_disconnect{description = Desc}, State, ErrorMsg) ->
+ {stop, {shutdown, {Desc, ErrorMsg}}, State}.
counterpart_versions(NumVsn, StrVsn, #ssh{role = server} = Ssh) ->
Ssh#ssh{c_vsn = NumVsn , c_version = StrVsn};
@@ -1003,45 +1399,67 @@ connected_fun(User, PeerAddr, Method, Opts) ->
catch Fun(User, PeerAddr, Method)
end.
-retry_fun(_, undefined, _) ->
+retry_fun(_, _, undefined, _) ->
ok;
-retry_fun(User, {error, Reason}, Opts) ->
+retry_fun(User, PeerAddr, {error, Reason}, Opts) ->
case proplists:get_value(failfun, Opts) of
undefined ->
ok;
Fun ->
- catch Fun(User, Reason)
+ do_retry_fun(Fun, User, PeerAddr, Reason)
end;
-retry_fun(User, Reason, Opts) ->
+retry_fun(User, PeerAddr, Reason, Opts) ->
case proplists:get_value(infofun, Opts) of
undefined ->
ok;
- Fun ->
- catch Fun(User, Reason)
+ Fun ->
+ do_retry_fun(Fun, User, PeerAddr, Reason)
end.
-ssh_info_handler(Options, Ssh, From) ->
- Info = ssh_info(Options, Ssh, []),
- ssh_connection_manager:send_msg({channel_requst_reply, From, Info}).
+do_retry_fun(Fun, User, PeerAddr, Reason) ->
+ case erlang:fun_info(Fun, arity) of
+ 2 -> %% Backwards compatible
+ catch Fun(User, Reason);
+ 3 ->
+ catch Fun(User, PeerAddr, Reason)
+ end.
-ssh_info([], _, Acc) ->
+ssh_info([], _State, Acc) ->
+ Acc;
+ssh_info([client_version | Rest], #state{ssh_params = #ssh{c_vsn = IntVsn,
+ c_version = StringVsn}} = State, Acc) ->
+ ssh_info(Rest, State, [{client_version, {IntVsn, StringVsn}} | Acc]);
+
+ssh_info([server_version | Rest], #state{ssh_params =#ssh{s_vsn = IntVsn,
+ s_version = StringVsn}} = State, Acc) ->
+ ssh_info(Rest, State, [{server_version, {IntVsn, StringVsn}} | Acc]);
+ssh_info([peer | Rest], #state{ssh_params = #ssh{peer = Peer}} = State, Acc) ->
+ ssh_info(Rest, State, [{peer, Peer} | Acc]);
+ssh_info([sockname | Rest], #state{socket = Socket} = State, Acc) ->
+ {ok, SockName} = inet:sockname(Socket),
+ ssh_info(Rest, State, [{sockname, SockName}|Acc]);
+ssh_info([user | Rest], #state{auth_user = User} = State, Acc) ->
+ ssh_info(Rest, State, [{user, User}|Acc]);
+ssh_info([ _ | Rest], State, Acc) ->
+ ssh_info(Rest, State, Acc).
+
+ssh_channel_info([], _, Acc) ->
Acc;
-ssh_info([client_version | Rest], #ssh{c_vsn = IntVsn,
- c_version = StringVsn} = SshParams, Acc) ->
- ssh_info(Rest, SshParams, [{client_version, {IntVsn, StringVsn}} | Acc]);
-
-ssh_info([server_version | Rest], #ssh{s_vsn = IntVsn,
- s_version = StringVsn} = SshParams, Acc) ->
- ssh_info(Rest, SshParams, [{server_version, {IntVsn, StringVsn}} | Acc]);
-
-ssh_info([peer | Rest], #ssh{peer = Peer} = SshParams, Acc) ->
- ssh_info(Rest, SshParams, [{peer, Peer} | Acc]);
-
-ssh_info([ _ | Rest], SshParams, Acc) ->
- ssh_info(Rest, SshParams, Acc).
+ssh_channel_info([recv_window | Rest], #channel{recv_window_size = WinSize,
+ recv_packet_size = Packsize
+ } = Channel, Acc) ->
+ ssh_channel_info(Rest, Channel, [{recv_window, {{win_size, WinSize},
+ {packet_size, Packsize}}} | Acc]);
+ssh_channel_info([send_window | Rest], #channel{send_window_size = WinSize,
+ send_packet_size = Packsize
+ } = Channel, Acc) ->
+ ssh_channel_info(Rest, Channel, [{send_window, {{win_size, WinSize},
+ {packet_size, Packsize}}} | Acc]);
+ssh_channel_info([ _ | Rest], Channel, Acc) ->
+ ssh_channel_info(Rest, Channel, Acc).
log_error(Reason) ->
Report = io_lib:format("Erlang ssh connection handler failed with reason: "
@@ -1050,3 +1468,101 @@ log_error(Reason) ->
[Reason, erlang:get_stacktrace()]),
error_logger:error_report(Report),
"Internal error".
+
+send_replies([], State) ->
+ State;
+send_replies([{connection_reply, Data} | Rest], #state{ssh_params = Ssh0} = State) ->
+ {Packet, Ssh} = ssh_transport:ssh_packet(Data, Ssh0),
+ send_msg(Packet, State),
+ send_replies(Rest, State#state{ssh_params = Ssh});
+send_replies([Msg | Rest], State) ->
+ catch send_reply(Msg),
+ send_replies(Rest, State).
+
+send_reply({channel_data, Pid, Data}) ->
+ Pid ! {ssh_cm, self(), Data};
+send_reply({channel_requst_reply, From, Data}) ->
+ gen_fsm:reply(From, Data);
+send_reply({flow_control, Cache, Channel, From, Msg}) ->
+ ssh_channel:cache_update(Cache, Channel#channel{flow_control = undefined}),
+ gen_fsm:reply(From, Msg);
+send_reply({flow_control, From, Msg}) ->
+ gen_fsm:reply(From, Msg).
+
+disconnect_fun(_, undefined) ->
+ ok;
+disconnect_fun(Reason, Opts) ->
+ case proplists:get_value(disconnectfun, Opts) of
+ undefined ->
+ ok;
+ Fun ->
+ catch Fun(Reason)
+ end.
+
+check_cache(#state{opts = Opts} = State, Cache) ->
+ %% Check the number of entries in Cache
+ case proplists:get_value(size, ets:info(Cache)) of
+ 0 ->
+ case proplists:get_value(idle_time, Opts, infinity) of
+ infinity ->
+ State;
+ Time ->
+ handle_idle_timer(Time, State)
+ end;
+ _ ->
+ State
+ end.
+
+handle_idle_timer(Time, #state{idle_timer_ref = undefined} = State) ->
+ TimerRef = erlang:send_after(Time, self(), {'EXIT', [], "Timeout"}),
+ State#state{idle_timer_ref=TimerRef};
+handle_idle_timer(_, State) ->
+ State.
+
+remove_timer_ref(State) ->
+ case State#state.idle_timer_ref of
+ infinity -> %% If the timer is not activated
+ State;
+ undefined -> %% If we already has cancelled the timer
+ State;
+ TimerRef -> %% Timer is active
+ erlang:cancel_timer(TimerRef),
+ State#state{idle_timer_ref = undefined}
+ end.
+
+socket_control(Socket, Pid, Transport) ->
+ case Transport:controlling_process(Socket, Pid) of
+ ok ->
+ send_event(Pid, socket_control);
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+handshake(Pid, Ref, Timeout) ->
+ receive
+ ssh_connected ->
+ erlang:demonitor(Ref),
+ {ok, Pid};
+ {Pid, not_connected, Reason} ->
+ {error, Reason};
+ {Pid, user_password} ->
+ Pass = io:get_password(),
+ Pid ! Pass,
+ handshake(Pid, Ref, Timeout);
+ {Pid, question} ->
+ Answer = io:get_line(""),
+ Pid ! Answer,
+ handshake(Pid, Ref, Timeout);
+ {'DOWN', _, process, Pid, {shutdown, Reason}} ->
+ {error, Reason};
+ {'DOWN', _, process, Pid, Reason} ->
+ {error, Reason}
+ after Timeout ->
+ stop(Pid),
+ {error, Timeout}
+ end.
+
+start_timeout(_,_, infinity) ->
+ ok;
+start_timeout(Channel, From, Time) ->
+ erlang:send_after(Time, self(), {timeout, {Channel, From}}).
diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl
deleted file mode 100644
index 99a0b6a7c8..0000000000
--- a/lib/ssh/src/ssh_connection_manager.erl
+++ /dev/null
@@ -1,916 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-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: Handles multiplexing to ssh channels and global connection
-%% requests e.i. the SSH Connection Protocol (RFC 4254), that provides
-%% interactive login sessions, remote execution of commands, forwarded
-%% TCP/IP connections, and forwarded X11 connections. Details of the
-%% protocol is implemented in ssh_connection.erl
-%% ----------------------------------------------------------------------
--module(ssh_connection_manager).
-
--behaviour(gen_server).
-
--include("ssh.hrl").
--include("ssh_connect.hrl").
--include("ssh_transport.hrl").
-
--export([start_link/1]).
-
--export([info/1, info/2,
- renegotiate/1, connection_info/2, channel_info/3,
- peer_addr/1, send_window/3, recv_window/3, adjust_window/3,
- close/2, stop/1, send/5,
- send_eof/2]).
-
--export([open_channel/6, reply_request/3, request/6, request/7, global_request/4, event/2, event/3, cast/2]).
-
-%% Internal application API and spawn
--export([send_msg/1, ssh_channel_info_handler/3]).
-
-%% gen_server callbacks
--export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- terminate/2, code_change/3]).
-
--define(DBG_MESSAGE, true).
-
--record(state,
- {
- role,
- client,
- starter,
- connection, % pid()
- connection_state, % #connection{}
- latest_channel_id = 0,
- opts,
- channel_args,
- idle_timer_ref, % timerref
- connected
- }).
-
-%%====================================================================
-%% Internal application API
-%%====================================================================
-
-start_link(Opts) ->
- gen_server:start_link(?MODULE, Opts, []).
-
-open_channel(ConnectionManager, ChannelType, ChannelSpecificData,
- InitialWindowSize, MaxPacketSize, Timeout) ->
- case (catch call(ConnectionManager, {open, self(), ChannelType,
- InitialWindowSize,
- MaxPacketSize, ChannelSpecificData},
- Timeout)) of
- {open, Channel} ->
- {ok, Channel};
- Error ->
- %% TODO: Best way?
- Error
- end.
-
-request(ConnectionManager, ChannelPid, ChannelId, Type, true, Data, Timeout) ->
- call(ConnectionManager, {request, ChannelPid, ChannelId, Type, Data}, Timeout);
-request(ConnectionManager, ChannelPid, ChannelId, Type, false, Data, _) ->
- cast(ConnectionManager, {request, ChannelPid, ChannelId, Type, Data}).
-
-request(ConnectionManager, ChannelId, Type, true, Data, Timeout) ->
- call(ConnectionManager, {request, ChannelId, Type, Data}, Timeout);
-request(ConnectionManager, ChannelId, Type, false, Data, _) ->
- cast(ConnectionManager, {request, ChannelId, Type, Data}).
-
-reply_request(ConnectionManager, Status, ChannelId) ->
- cast(ConnectionManager, {reply_request, Status, ChannelId}).
-
-global_request(ConnectionManager, Type, true = Reply, Data) ->
- case call(ConnectionManager,
- {global_request, self(), Type, Reply, Data}) of
- {ssh_cm, ConnectionManager, {success, _}} ->
- ok;
- {ssh_cm, ConnectionManager, {failure, _}} ->
- error
- end;
-
-global_request(ConnectionManager, Type, false = Reply, Data) ->
- cast(ConnectionManager, {global_request, self(), Type, Reply, Data}).
-
-event(ConnectionManager, BinMsg, ErrorMsg) ->
- call(ConnectionManager, {ssh_msg, self(), BinMsg, ErrorMsg}).
-event(ConnectionManager, BinMsg) ->
- call(ConnectionManager, {ssh_msg, self(), BinMsg}).
-info(ConnectionManager) ->
- info(ConnectionManager, {info, all}).
-
-info(ConnectionManager, ChannelProcess) ->
- call(ConnectionManager, {info, ChannelProcess}).
-
-%% TODO: Do we really want this function? Should not
-%% renegotiation be triggered by configurable timer
-%% or amount of data sent counter!
-renegotiate(ConnectionManager) ->
- cast(ConnectionManager, renegotiate).
-renegotiate_data(ConnectionManager) ->
- cast(ConnectionManager, renegotiate_data).
-connection_info(ConnectionManager, Options) ->
- call(ConnectionManager, {connection_info, Options}).
-
-channel_info(ConnectionManager, ChannelId, Options) ->
- call(ConnectionManager, {channel_info, ChannelId, Options}).
-
-%% Replaced by option peer to connection_info/2 keep for now
-%% for Backwards compatibility!
-peer_addr(ConnectionManager) ->
- call(ConnectionManager, {peer_addr, self()}).
-
-%% Backwards compatibility!
-send_window(ConnectionManager, Channel, TimeOut) ->
- call(ConnectionManager, {send_window, Channel}, TimeOut).
-%% Backwards compatibility!
-recv_window(ConnectionManager, Channel, TimeOut) ->
- call(ConnectionManager, {recv_window, Channel}, TimeOut).
-
-adjust_window(ConnectionManager, Channel, Bytes) ->
- cast(ConnectionManager, {adjust_window, Channel, Bytes}).
-
-close(ConnectionManager, ChannelId) ->
- case call(ConnectionManager, {close, ChannelId}) of
- ok ->
- ok;
- {error, channel_closed} ->
- ok
- end.
-
-stop(ConnectionManager) ->
- case call(ConnectionManager, stop) of
- ok ->
- ok;
- {error, channel_closed} ->
- ok
- end.
-
-send(ConnectionManager, ChannelId, Type, Data, Timeout) ->
- call(ConnectionManager, {data, ChannelId, Type, Data}, Timeout).
-
-send_eof(ConnectionManager, ChannelId) ->
- call(ConnectionManager, {eof, ChannelId}).
-
-%%====================================================================
-%% gen_server callbacks
-%%====================================================================
-
-%%--------------------------------------------------------------------
-%% Function: init(Args) -> {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%--------------------------------------------------------------------
-init([server, _Socket, Opts]) ->
- process_flag(trap_exit, true),
- ssh_bits:install_messages(ssh_connection:messages()),
- Cache = ssh_channel:cache_create(),
- {ok, #state{role = server,
- connection_state = #connection{channel_cache = Cache,
- channel_id_seed = 0,
- port_bindings = [],
- requests = []},
- opts = Opts,
- connected = false}};
-
-init([client, Opts]) ->
- process_flag(trap_exit, true),
- {links, [Parent]} = process_info(self(), links),
- ssh_bits:install_messages(ssh_connection:messages()),
- Cache = ssh_channel:cache_create(),
- Address = proplists:get_value(address, Opts),
- Port = proplists:get_value(port, Opts),
- SocketOpts = proplists:get_value(socket_opts, Opts),
- Options = proplists:get_value(ssh_opts, Opts),
- ChannelPid = proplists:get_value(channel_pid, Opts),
- self() !
- {start_connection, client, [Parent, Address, Port, SocketOpts, Options]},
- TimerRef = get_idle_time(Options),
-
- {ok, #state{role = client,
- client = ChannelPid,
- connection_state = #connection{channel_cache = Cache,
- channel_id_seed = 0,
- port_bindings = [],
- connection_supervisor = Parent,
- requests = []},
- opts = Opts,
- idle_timer_ref = TimerRef,
- connected = false}}.
-
-%%--------------------------------------------------------------------
-%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
-%% {reply, Reply, State, Timeout} |
-%% {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, Reply, State} |
-%% {stop, Reason, State}
-%% Description: Handling call messages
-%%--------------------------------------------------------------------
-handle_call({request, ChannelPid, ChannelId, Type, Data}, From, State0) ->
- {{replies, Replies}, State} = handle_request(ChannelPid,
- ChannelId, Type, Data,
- true, From, State0),
- %% Sends message to the connection handler process, reply to
- %% channel is sent later when reply arrives from the connection
- %% handler.
- lists:foreach(fun send_msg/1, Replies),
- SshOpts = proplists:get_value(ssh_opts, State0#state.opts),
- case proplists:get_value(idle_time, SshOpts) of
- infinity ->
- ok;
- _IdleTime ->
- erlang:send_after(5000, self(), {check_cache, [], []})
- end,
- {noreply, State};
-
-handle_call({request, ChannelId, Type, Data}, From, State0) ->
- {{replies, Replies}, State} = handle_request(ChannelId, Type, Data,
- true, From, State0),
- %% Sends message to the connection handler process, reply to
- %% channel is sent later when reply arrives from the connection
- %% handler.
- lists:foreach(fun send_msg/1, Replies),
- {noreply, State};
-
-%% Message from ssh_connection_handler
-handle_call({ssh_msg, Pid, Msg}, From,
- #state{connection_state = Connection0,
- role = Role, opts = Opts, connected = IsConnected,
- client = ClientPid}
- = State) ->
-
- %% To avoid that not all data sent by the other side is processes before
- %% possible crash in ssh_connection_handler takes down the connection.
- gen_server:reply(From, ok),
- ConnectionMsg = decode_ssh_msg(Msg),
- try ssh_connection:handle_msg(ConnectionMsg, Connection0, Pid, Role) of
- {{replies, Replies}, Connection} ->
- lists:foreach(fun send_msg/1, Replies),
- {noreply, State#state{connection_state = Connection}};
- {noreply, Connection} ->
- {noreply, State#state{connection_state = Connection}};
- {disconnect, {_, Reason}, {{replies, Replies}, Connection}}
- when Role == client andalso (not IsConnected) ->
- lists:foreach(fun send_msg/1, Replies),
- ClientPid ! {self(), not_connected, Reason},
- {stop, {shutdown, normal}, State#state{connection = Connection}};
- {disconnect, Reason, {{replies, Replies}, Connection}} ->
- lists:foreach(fun send_msg/1, Replies),
- SSHOpts = proplists:get_value(ssh_opts, Opts),
- disconnect_fun(Reason, SSHOpts),
- {stop, {shutdown, normal}, State#state{connection_state = Connection}}
- catch
- _:Error ->
- {disconnect, Reason, {{replies, Replies}, Connection}} =
- ssh_connection:handle_msg(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
- description = "Internal error",
- language = "en"}, Connection0, undefined,
- Role),
- lists:foreach(fun send_msg/1, Replies),
- SSHOpts = proplists:get_value(ssh_opts, Opts),
- disconnect_fun(Reason, SSHOpts),
- {stop, {shutdown, Error}, State#state{connection_state = Connection}}
- end;
-handle_call({ssh_msg, Pid, Msg, ErrorMsg}, From,
- #state{connection_state = Connection0,
- role = Role, opts = Opts, connected = IsConnected,
- client = ClientPid}
- = State) ->
-
- %% To avoid that not all data sent by the other side is processes before
- %% possible crash in ssh_connection_handler takes down the connection.
- gen_server:reply(From, ok),
- ConnectionMsg = decode_ssh_msg(Msg),
- try ssh_connection:handle_msg(ConnectionMsg, Connection0, Pid, Role) of
- {{replies, Replies}, Connection} ->
- lists:foreach(fun send_msg/1, Replies),
- {noreply, State#state{connection_state = Connection}};
- {noreply, Connection} ->
- {noreply, State#state{connection_state = Connection}};
- {disconnect, {_, Reason}, {{replies, Replies}, Connection}}
- when Role == client andalso (not IsConnected) ->
- lists:foreach(fun send_msg/1, Replies),
- ClientPid ! {self(), not_connected, {Reason, ErrorMsg}},
- {stop, {shutdown, normal}, State#state{connection = Connection}};
- {disconnect, Reason, {{replies, Replies}, Connection}} ->
- lists:foreach(fun send_msg/1, Replies),
- SSHOpts = proplists:get_value(ssh_opts, Opts),
- disconnect_fun(Reason, SSHOpts),
- {stop, {shutdown, normal}, State#state{connection_state = Connection}}
- catch
- _:Error ->
- {disconnect, Reason, {{replies, Replies}, Connection}} =
- ssh_connection:handle_msg(
- #ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
- description = "Internal error",
- language = "en"}, Connection0, undefined,
- Role),
- lists:foreach(fun send_msg/1, Replies),
- SSHOpts = proplists:get_value(ssh_opts, Opts),
- disconnect_fun(Reason, SSHOpts),
- {stop, {shutdown, Error}, State#state{connection_state = Connection}}
- end;
-handle_call({global_request, Pid, _, _, _} = Request, From,
- #state{connection_state =
- #connection{channel_cache = Cache}} = State0) ->
- State1 = handle_global_request(Request, State0),
- Channel = ssh_channel:cache_find(Pid, Cache),
- State = add_request(true, Channel#channel.local_id, From, State1),
- {noreply, State};
-
-handle_call({data, ChannelId, Type, Data}, From,
- #state{connection_state = #connection{channel_cache = _Cache}
- = Connection0,
- connection = ConnectionPid} = State) ->
- channel_data(ChannelId, Type, Data, Connection0, ConnectionPid, From,
- State);
-
-handle_call({eof, ChannelId}, _From,
- #state{connection = Pid, connection_state =
- #connection{channel_cache = Cache}} = State) ->
- case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{remote_id = Id, sent_close = false} ->
- send_msg({connection_reply, Pid,
- ssh_connection:channel_eof_msg(Id)}),
- {reply, ok, State};
- _ ->
- {reply, {error,closed}, State}
- end;
-
-handle_call({connection_info, Options}, From,
- #state{connection = Connection} = State) ->
- ssh_connection_handler:connection_info(Connection, From, Options),
- %% Reply will be sent by the connection handler by calling
- %% ssh_connection_handler:send_msg/1.
- {noreply, State};
-
-handle_call({channel_info, ChannelId, Options}, From,
- #state{connection_state = #connection{channel_cache = Cache}} = State) ->
-
- case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{} = Channel ->
- spawn(?MODULE, ssh_channel_info_handler, [Options, Channel, From]),
- {noreply, State};
- undefined ->
- {reply, []}
- end;
-
-handle_call({info, ChannelPid}, _From,
- #state{connection_state =
- #connection{channel_cache = Cache}} = State) ->
- Result = ssh_channel:cache_foldl(
- fun(Channel, Acc) when ChannelPid == all;
- Channel#channel.user == ChannelPid ->
- [Channel | Acc];
- (_, Acc) ->
- Acc
- end, [], Cache),
- {reply, {ok, Result}, State};
-
-handle_call({open, ChannelPid, Type, InitialWindowSize, MaxPacketSize, Data},
- From, #state{connection = Pid,
- connection_state =
- #connection{channel_cache = Cache}} = State0) ->
- erlang:monitor(process, ChannelPid),
- {ChannelId, State1} = new_channel_id(State0),
- Msg = ssh_connection:channel_open_msg(Type, ChannelId,
- InitialWindowSize,
- MaxPacketSize, Data),
- send_msg({connection_reply, Pid, Msg}),
- Channel = #channel{type = Type,
- sys = "none",
- user = ChannelPid,
- local_id = ChannelId,
- recv_window_size = InitialWindowSize,
- recv_packet_size = MaxPacketSize},
- ssh_channel:cache_update(Cache, Channel),
- State = add_request(true, ChannelId, From, State1),
- {noreply, remove_timer_ref(State)};
-
-handle_call({send_window, ChannelId}, _From,
- #state{connection_state =
- #connection{channel_cache = Cache}} = State) ->
- Reply = case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{send_window_size = WinSize,
- send_packet_size = Packsize} ->
- {ok, {WinSize, Packsize}};
- undefined ->
- {error, einval}
- end,
- {reply, Reply, State};
-
-handle_call({recv_window, ChannelId}, _From,
- #state{connection_state = #connection{channel_cache = Cache}}
- = State) ->
-
- Reply = case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{recv_window_size = WinSize,
- recv_packet_size = Packsize} ->
- {ok, {WinSize, Packsize}};
- undefined ->
- {error, einval}
- end,
- {reply, Reply, State};
-
-%% Replaced by option peer to connection_info/2 keep for now
-%% for Backwards compatibility!
-handle_call({peer_addr, _ChannelId}, _From,
- #state{connection = Pid} = State) ->
- Reply = ssh_connection_handler:peer_address(Pid),
- {reply, Reply, State};
-
-handle_call(opts, _, #state{opts = Opts} = State) ->
- {reply, Opts, State};
-
-handle_call({close, ChannelId}, _,
- #state{connection = Pid, connection_state =
- #connection{channel_cache = Cache}} = State) ->
- case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{remote_id = Id} = Channel ->
- send_msg({connection_reply, Pid,
- ssh_connection:channel_close_msg(Id)}),
- ssh_channel:cache_update(Cache, Channel#channel{sent_close = true}),
- SshOpts = proplists:get_value(ssh_opts, State#state.opts),
- case proplists:get_value(idle_time, SshOpts) of
- infinity ->
- ok;
- _IdleTime ->
- erlang:send_after(5000, self(), {check_cache, [], []})
- end,
- {reply, ok, State};
- undefined ->
- {reply, ok, State}
- end;
-
-handle_call(stop, _, #state{connection_state = Connection0,
- role = Role,
- opts = Opts} = State) ->
- {disconnect, Reason, {{replies, Replies}, Connection}} =
- ssh_connection:handle_msg(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_BY_APPLICATION,
- description = "User closed down connection",
- language = "en"}, Connection0, undefined,
- Role),
- lists:foreach(fun send_msg/1, Replies),
- SSHOpts = proplists:get_value(ssh_opts, Opts),
- disconnect_fun(Reason, SSHOpts),
- {stop, normal, ok, State#state{connection_state = Connection}};
-
-%% API violation make it the violaters problem
-%% by ignoring it. The violating process will get
-%% a timeout or hang.
-handle_call(_, _, State) ->
- {noreply, State}.
-
-%%--------------------------------------------------------------------
-%% Function: handle_cast(Msg, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
-%% Description: Handling cast messages
-%%--------------------------------------------------------------------
-handle_cast({request, ChannelPid, ChannelId, Type, Data}, State0) ->
- {{replies, Replies}, State} = handle_request(ChannelPid, ChannelId,
- Type, Data,
- false, none, State0),
- lists:foreach(fun send_msg/1, Replies),
- {noreply, State};
-
-handle_cast({request, ChannelId, Type, Data}, State0) ->
- {{replies, Replies}, State} = handle_request(ChannelId, Type, Data,
- false, none, State0),
- lists:foreach(fun send_msg/1, Replies),
- {noreply, State};
-
-handle_cast({reply_request, Status, ChannelId}, #state{connection_state =
- #connection{channel_cache = Cache}} = State0) ->
- State = case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{remote_id = RemoteId} ->
- cm_message({Status, RemoteId}, State0);
- undefined ->
- State0
- end,
- {noreply, State};
-
-handle_cast({global_request, _, _, _, _} = Request, State0) ->
- State = handle_global_request(Request, State0),
- {noreply, State};
-
-handle_cast(renegotiate, #state{connection = Pid} = State) ->
- ssh_connection_handler:renegotiate(Pid),
- {noreply, State};
-handle_cast(renegotiate_data, #state{connection = Pid} = State) ->
- ssh_connection_handler:renegotiate_data(Pid),
- {noreply, State};
-handle_cast({adjust_window, ChannelId, Bytes},
- #state{connection = Pid, connection_state =
- #connection{channel_cache = Cache}} = State) ->
- case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{recv_window_size = WinSize, remote_id = Id} = Channel ->
- ssh_channel:cache_update(Cache, Channel#channel{recv_window_size =
- WinSize + Bytes}),
- Msg = ssh_connection:channel_adjust_window_msg(Id, Bytes),
- send_msg({connection_reply, Pid, Msg});
- undefined ->
- ignore
- end,
- {noreply, State};
-
-handle_cast({success, ChannelId}, #state{connection = Pid} = State) ->
- Msg = ssh_connection:channel_success_msg(ChannelId),
- send_msg({connection_reply, Pid, Msg}),
- {noreply, State};
-
-handle_cast({failure, ChannelId}, #state{connection = Pid} = State) ->
- Msg = ssh_connection:channel_failure_msg(ChannelId),
- send_msg({connection_reply, Pid, Msg}),
- {noreply, State}.
-
-%%--------------------------------------------------------------------
-%% Function: handle_info(Info, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
-%% Description: Handling all non call/cast messages
-%%--------------------------------------------------------------------
-handle_info({start_connection, server,
- [Address, Port, Socket, Options, SubSysSup]},
- #state{connection_state = CState} = State) ->
- {ok, Connection} = ssh_transport:accept(Address, Port, Socket, Options),
- Shell = proplists:get_value(shell, Options),
- Exec = proplists:get_value(exec, Options),
- CliSpec = proplists:get_value(ssh_cli, Options, {ssh_cli, [Shell]}),
- ssh_connection_handler:send_event(Connection, socket_control),
- erlang:send_after(60000, self(), rekey_data),
- {noreply, State#state{connection = Connection,
- connection_state =
- CState#connection{address = Address,
- port = Port,
- cli_spec = CliSpec,
- options = Options,
- exec = Exec,
- sub_system_supervisor = SubSysSup
- }}};
-
-handle_info({start_connection, client,
- [Parent, Address, Port, SocketOpts, Options]},
- #state{client = Pid} = State) ->
- case (catch ssh_transport:connect(Parent, Address,
- Port, SocketOpts, Options)) of
- {ok, Connection} ->
- erlang:send_after(60000, self(), rekey_data),
- erlang:send_after(3600000, self(), rekey),
- {noreply, State#state{connection = Connection}};
- Reason ->
- Pid ! {self(), not_connected, Reason},
- {stop, {shutdown, normal}, State}
- end;
-handle_info({check_cache, _ , _},
- #state{connection_state =
- #connection{channel_cache = Cache}} = State) ->
- {noreply, check_cache(State, Cache)};
-handle_info({ssh_cm, _Sender, Msg}, State0) ->
- %% Backwards compatibility!
- State = cm_message(Msg, State0),
- {noreply, State};
-
-%% Nop backwards compatibility
-handle_info({same_user, _}, State) ->
- {noreply, State};
-
-handle_info(ssh_connected, #state{role = client, client = Pid}
- = State) ->
- Pid ! {self(), is_connected},
- {noreply, State#state{connected = true, opts = handle_password(State#state.opts)}};
-
-handle_info(ssh_connected, #state{role = server} = State) ->
- {noreply, State#state{connected = true}};
-
-%%% Handle that ssh channels user process goes down
-handle_info({'DOWN', _Ref, process, ChannelPid, _Reason}, State) ->
- handle_down(handle_channel_down(ChannelPid, State));
-
-%%% So that terminate will be run when supervisor is shutdown
-handle_info({'EXIT', _Sup, Reason}, State) ->
- {stop, Reason, State};
-handle_info(rekey, State) ->
- renegotiate(self()),
- erlang:send_after(3600000, self(), rekey),
- {noreply, State};
-handle_info(rekey_data, State) ->
- renegotiate_data(self()),
- erlang:send_after(60000, self(), rekey_data),
- {noreply, State}.
-handle_password(Opts) ->
- handle_rsa_password(handle_dsa_password(handle_normal_password(Opts))).
-handle_normal_password(Opts) ->
- case proplists:get_value(ssh_opts, Opts, false) of
- false ->
- Opts;
- SshOpts ->
- case proplists:get_value(password, SshOpts, false) of
- false ->
- Opts;
- _Password ->
- NewOpts = [{password, undefined}|lists:keydelete(password, 1, SshOpts)],
- [{ssh_opts, NewOpts}|lists:keydelete(ssh_opts, 1, Opts)]
- end
- end.
-handle_dsa_password(Opts) ->
- case proplists:get_value(ssh_opts, Opts, false) of
- false ->
- Opts;
- SshOpts ->
- case proplists:get_value(dsa_pass_phrase, SshOpts, false) of
- false ->
- Opts;
- _Password ->
- NewOpts = [{dsa_pass_phrase, undefined}|lists:keydelete(dsa_pass_phrase, 1, SshOpts)],
- [{ssh_opts, NewOpts}|lists:keydelete(ssh_opts, 1, Opts)]
- end
- end.
-handle_rsa_password(Opts) ->
- case proplists:get_value(ssh_opts, Opts, false) of
- false ->
- Opts;
- SshOpts ->
- case proplists:get_value(rsa_pass_phrase, SshOpts, false) of
- false ->
- Opts;
- _Password ->
- NewOpts = [{rsa_pass_phrase, undefined}|lists:keydelete(rsa_pass_phrase, 1, SshOpts)],
- [{ssh_opts, NewOpts}|lists:keydelete(ssh_opts, 1, Opts)]
- end
- end.
-%%--------------------------------------------------------------------
-%% Function: terminate(Reason, State) -> void()
-%% Description: This function is called by a gen_server when it is about to
-%% terminate. It should be the opposite of Module:init/1 and do any necessary
-%% cleaning up. When it returns, the gen_server terminates with Reason.
-%% The return value is ignored.
-%%--------------------------------------------------------------------
-terminate(_Reason, #state{role = client,
- connection_state =
- #connection{connection_supervisor = Supervisor}}) ->
- sshc_sup:stop_child(Supervisor);
-
-terminate(_Reason, #state{role = server,
- connection_state =
- #connection{sub_system_supervisor = SubSysSup},
- opts = Opts}) ->
- Address = proplists:get_value(address, Opts),
- Port = proplists:get_value(port, Opts),
- SystemSup = ssh_system_sup:system_supervisor(Address, Port),
- ssh_system_sup:stop_subsystem(SystemSup, SubSysSup).
-
-%%--------------------------------------------------------------------
-%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
-%% Description: Convert process state when code is changed
-%%--------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
-get_idle_time(SshOptions) ->
- case proplists:get_value(idle_time, SshOptions) of
- infinity ->
- infinity;
- _IdleTime -> %% We dont want to set the timeout on first connect
- undefined
- end.
-check_cache(State, Cache) ->
- %% Check the number of entries in Cache
- case proplists:get_value(size, ets:info(Cache)) of
- 0 ->
- Opts = proplists:get_value(ssh_opts, State#state.opts),
- case proplists:get_value(idle_time, Opts) of
- infinity ->
- State;
- undefined ->
- State;
- Time ->
- case State#state.idle_timer_ref of
- undefined ->
- TimerRef = erlang:send_after(Time, self(), {'EXIT', [], "Timeout"}),
- State#state{idle_timer_ref=TimerRef};
- _ ->
- State
- end
- end;
- _ ->
- State
- end.
-remove_timer_ref(State) ->
- case State#state.idle_timer_ref of
- infinity -> %% If the timer is not activated
- State;
- undefined -> %% If we already has cancelled the timer
- State;
- TimerRef -> %% Timer is active
- erlang:cancel_timer(TimerRef),
- State#state{idle_timer_ref = undefined}
- end.
-channel_data(Id, Type, Data, Connection0, ConnectionPid, From, State) ->
- case ssh_connection:channel_data(Id, Type, Data, Connection0,
- ConnectionPid, From) of
- {{replies, Replies}, Connection} ->
- lists:foreach(fun send_msg/1, Replies),
- {noreply, State#state{connection_state = Connection}};
- {noreply, Connection} ->
- {noreply, State#state{connection_state = Connection}}
- end.
-
-call(Pid, Msg) ->
- call(Pid, Msg, infinity).
-call(Pid, Msg, Timeout) ->
- try gen_server:call(Pid, Msg, Timeout) of
- Result ->
- Result
- catch
- exit:{timeout, _} ->
- {error, timeout};
- exit:{normal, _} ->
- {error, channel_closed};
- exit:{{shutdown, _}, _} ->
- {error, channel_closed};
- exit:{noproc,_} ->
- {error, channel_closed}
- end.
-
-cast(Pid, Msg) ->
- gen_server:cast(Pid, Msg).
-
-decode_ssh_msg(BinMsg) when is_binary(BinMsg)->
- ssh_bits:decode(BinMsg);
-decode_ssh_msg(Msg) ->
- Msg.
-
-
-send_msg(Msg) ->
- catch do_send_msg(Msg).
-do_send_msg({channel_data, Pid, Data}) ->
- Pid ! {ssh_cm, self(), Data};
-do_send_msg({channel_requst_reply, From, Data}) ->
- gen_server:reply(From, Data);
-do_send_msg({connection_reply, Pid, Data}) ->
- Msg = ssh_bits:encode(Data),
- ssh_connection_handler:send(Pid, Msg);
-do_send_msg({flow_control, Cache, Channel, From, Msg}) ->
- ssh_channel:cache_update(Cache, Channel#channel{flow_control = undefined}),
- gen_server:reply(From, Msg);
-do_send_msg({flow_control, From, Msg}) ->
- gen_server:reply(From, Msg).
-
-handle_request(ChannelPid, ChannelId, Type, Data, WantReply, From,
- #state{connection = Pid,
- connection_state =
- #connection{channel_cache = Cache}} = State0) ->
- case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{remote_id = Id} = Channel ->
- update_sys(Cache, Channel, Type, ChannelPid),
- Msg = ssh_connection:channel_request_msg(Id, Type,
- WantReply, Data),
- Replies = [{connection_reply, Pid, Msg}],
- State = add_request(WantReply, ChannelId, From, State0),
- {{replies, Replies}, State};
- undefined ->
- {{replies, []}, State0}
- end.
-
-handle_request(ChannelId, Type, Data, WantReply, From,
- #state{connection = Pid,
- connection_state =
- #connection{channel_cache = Cache}} = State0) ->
- case ssh_channel:cache_lookup(Cache, ChannelId) of
- #channel{remote_id = Id} ->
- Msg = ssh_connection:channel_request_msg(Id, Type,
- WantReply, Data),
- Replies = [{connection_reply, Pid, Msg}],
- State = add_request(WantReply, ChannelId, From, State0),
- {{replies, Replies}, State};
- undefined ->
- {{replies, []}, State0}
- end.
-
-handle_down({{replies, Replies}, State}) ->
- lists:foreach(fun send_msg/1, Replies),
- {noreply, State}.
-
-handle_channel_down(ChannelPid, #state{connection_state =
- #connection{channel_cache = Cache}} =
- State) ->
- ssh_channel:cache_foldl(
- fun(Channel, Acc) when Channel#channel.user == ChannelPid ->
- ssh_channel:cache_delete(Cache,
- Channel#channel.local_id),
- Acc;
- (_,Acc) ->
- Acc
- end, [], Cache),
- {{replies, []}, check_cache(State, Cache)}.
-
-update_sys(Cache, Channel, Type, ChannelPid) ->
- ssh_channel:cache_update(Cache,
- Channel#channel{sys = Type, user = ChannelPid}).
-
-add_request(false, _ChannelId, _From, State) ->
- State;
-add_request(true, ChannelId, From, #state{connection_state =
- #connection{requests = Requests0} =
- Connection} = State) ->
- Requests = [{ChannelId, From} | Requests0],
- State#state{connection_state = Connection#connection{requests = Requests}}.
-
-new_channel_id(#state{connection_state = #connection{channel_id_seed = Id} =
- Connection}
- = State) ->
- {Id, State#state{connection_state =
- Connection#connection{channel_id_seed = Id + 1}}}.
-
-handle_global_request({global_request, ChannelPid,
- "tcpip-forward" = Type, WantReply,
- <<?UINT32(IPLen),
- IP:IPLen/binary, ?UINT32(Port)>> = Data},
- #state{connection = ConnectionPid,
- connection_state =
- #connection{channel_cache = Cache}
- = Connection0} = State) ->
- ssh_channel:cache_update(Cache, #channel{user = ChannelPid,
- type = "forwarded-tcpip",
- sys = none}),
- Connection = ssh_connection:bind(IP, Port, ChannelPid, Connection0),
- Msg = ssh_connection:global_request_msg(Type, WantReply, Data),
- send_msg({connection_reply, ConnectionPid, Msg}),
- State#state{connection_state = Connection};
-
-handle_global_request({global_request, _Pid, "cancel-tcpip-forward" = Type,
- WantReply, <<?UINT32(IPLen),
- IP:IPLen/binary, ?UINT32(Port)>> = Data},
- #state{connection = Pid,
- connection_state = Connection0} = State) ->
- Connection = ssh_connection:unbind(IP, Port, Connection0),
- Msg = ssh_connection:global_request_msg(Type, WantReply, Data),
- send_msg({connection_reply, Pid, Msg}),
- State#state{connection_state = Connection};
-
-handle_global_request({global_request, _Pid, "cancel-tcpip-forward" = Type,
- WantReply, Data}, #state{connection = Pid} = State) ->
- Msg = ssh_connection:global_request_msg(Type, WantReply, Data),
- send_msg({connection_reply, Pid, Msg}),
- State.
-
-cm_message(Msg, State) ->
- {noreply, NewState} = handle_cast(Msg, State),
- NewState.
-
-disconnect_fun(Reason, Opts) ->
- case proplists:get_value(disconnectfun, Opts) of
- undefined ->
- ok;
- Fun ->
- catch Fun(Reason)
- end.
-
-ssh_channel_info_handler(Options, Channel, From) ->
- Info = ssh_channel_info(Options, Channel, []),
- send_msg({channel_requst_reply, From, Info}).
-
-ssh_channel_info([], _, Acc) ->
- Acc;
-
-ssh_channel_info([recv_window | Rest], #channel{recv_window_size = WinSize,
- recv_packet_size = Packsize
- } = Channel, Acc) ->
- ssh_channel_info(Rest, Channel, [{recv_window, {{win_size, WinSize},
- {packet_size, Packsize}}} | Acc]);
-ssh_channel_info([send_window | Rest], #channel{send_window_size = WinSize,
- send_packet_size = Packsize
- } = Channel, Acc) ->
- ssh_channel_info(Rest, Channel, [{send_window, {{win_size, WinSize},
- {packet_size, Packsize}}} | Acc]);
-ssh_channel_info([ _ | Rest], Channel, Acc) ->
- ssh_channel_info(Rest, Channel, Acc).
-
-
-
diff --git a/lib/ssh/src/ssh_connection_sup.erl b/lib/ssh/src/ssh_connection_sup.erl
index b620056310..c5abc8f23b 100644
--- a/lib/ssh/src/ssh_connection_sup.erl
+++ b/lib/ssh/src/ssh_connection_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -25,8 +25,9 @@
-behaviour(supervisor).
--export([start_link/1, start_handler_child/2, start_manager_child/2,
- connection_manager/1]).
+%% API
+-export([start_link/1]).
+-export([start_child/2]).
%% Supervisor callback
-export([init/1]).
@@ -37,83 +38,23 @@
start_link(Args) ->
supervisor:start_link(?MODULE, [Args]).
-%% Will be called from the manager child process
-start_handler_child(Sup, Args) ->
- [Spec] = child_specs(handler, Args),
- supervisor:start_child(Sup, Spec).
-
-%% Will be called from the acceptor process
-start_manager_child(Sup, Args) ->
- [Spec] = child_specs(manager, Args),
- supervisor:start_child(Sup, Spec).
-
-connection_manager(SupPid) ->
- try supervisor:which_children(SupPid) of
- Children ->
- {ok, ssh_connection_manager(Children)}
- catch exit:{noproc,_} ->
- {ok, undefined}
- end.
+start_child(Sup, Args) ->
+ supervisor:start_child(Sup, Args).
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
-init([Args]) ->
- RestartStrategy = one_for_all,
+init(_) ->
+ RestartStrategy = simple_one_for_one,
MaxR = 0,
MaxT = 3600,
- Children = child_specs(Args),
- {ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
-
-%%%=========================================================================
-%%% Internal functions
-%%%=========================================================================
-child_specs(Opts) ->
- case proplists:get_value(role, Opts) of
- client ->
- child_specs(manager, [client | Opts]);
- server ->
- %% Children started by acceptor process
- []
- end.
-
-% The manager process starts the handler process
-child_specs(manager, Opts) ->
- [manager_spec(Opts)];
-child_specs(handler, Opts) ->
- [handler_spec(Opts)].
-
-manager_spec([server = Role, Socket, Opts]) ->
- Name = make_ref(),
- StartFunc = {ssh_connection_manager, start_link, [[Role, Socket, Opts]]},
- Restart = temporary,
- Shutdown = 3600,
- Modules = [ssh_connection_manager],
- Type = worker,
- {Name, StartFunc, Restart, Shutdown, Type, Modules};
-
-manager_spec([client = Role | Opts]) ->
- Name = make_ref(),
- StartFunc = {ssh_connection_manager, start_link, [[Role, Opts]]},
- Restart = temporary,
- Shutdown = 3600,
- Modules = [ssh_connection_manager],
- Type = worker,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
-handler_spec([Role, Socket, Opts]) ->
- Name = make_ref(),
- StartFunc = {ssh_connection_handler,
- start_link, [Role, self(), Socket, Opts]},
- Restart = temporary,
- Shutdown = 3600,
+ Name = undefined, % As simple_one_for_one is used.
+ StartFunc = {ssh_connection_handler, start_link, []},
+ Restart = temporary, % E.g. should not be restarted
+ Shutdown = 4000,
Modules = [ssh_connection_handler],
Type = worker,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
-ssh_connection_manager([]) ->
- undefined;
-ssh_connection_manager([{_, Child, _, [ssh_connection_manager]} | _]) ->
- Child;
-ssh_connection_manager([_ | Rest]) ->
- ssh_connection_manager(Rest).
+ ChildSpec = {Name, StartFunc, Restart, Shutdown, Type, Modules},
+ {ok, {{RestartStrategy, MaxR, MaxT}, [ChildSpec]}}.
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
new file mode 100644
index 0000000000..7bd0375521
--- /dev/null
+++ b/lib/ssh/src/ssh_message.erl
@@ -0,0 +1,529 @@
+%%
+%% %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(ssh_message).
+
+-include_lib("public_key/include/public_key.hrl").
+
+-include("ssh.hrl").
+-include("ssh_connect.hrl").
+-include("ssh_auth.hrl").
+-include("ssh_transport.hrl").
+
+-export([encode/1, decode/1, encode_host_key/1, decode_keyboard_interactive_prompts/2]).
+
+encode(#ssh_msg_global_request{
+ name = Name,
+ want_reply = Bool,
+ data = Data}) ->
+ ssh_bits:encode([?SSH_MSG_GLOBAL_REQUEST,
+ Name, Bool, Data], [byte, string, boolean, '...']);
+encode(#ssh_msg_request_success{data = Data}) ->
+ <<?BYTE(?SSH_MSG_REQUEST_SUCCESS), Data/binary>>;
+encode(#ssh_msg_request_failure{}) ->
+ <<?BYTE(?SSH_MSG_REQUEST_FAILURE)>>;
+encode(#ssh_msg_channel_open{
+ channel_type = Type,
+ sender_channel = Sender,
+ initial_window_size = Window,
+ maximum_packet_size = Max,
+ data = Data
+ }) ->
+ ssh_bits:encode([?SSH_MSG_CHANNEL_OPEN,
+ Type, Sender, Window, Max, Data], [byte, string, uint32,
+ uint32, uint32, '...']);
+encode(#ssh_msg_channel_open_confirmation{
+ recipient_channel = Recipient,
+ sender_channel = Sender,
+ initial_window_size = InitWindowSize,
+ maximum_packet_size = MaxPacketSize,
+ data = Data
+ }) ->
+ ssh_bits:encode([?SSH_MSG_CHANNEL_OPEN_CONFIRMATION, Recipient,
+ Sender, InitWindowSize, MaxPacketSize, Data],
+ [byte, uint32, uint32, uint32, uint32, '...']);
+encode(#ssh_msg_channel_open_failure{
+ recipient_channel = Recipient,
+ reason = Reason,
+ description = Desc,
+ lang = Lang
+ }) ->
+ ssh_bits:encode([?SSH_MSG_CHANNEL_OPEN_FAILURE, Recipient,
+ Reason, Desc, Lang], [byte, uint32, uint32, string, string]);
+encode(#ssh_msg_channel_window_adjust{
+ recipient_channel = Recipient,
+ bytes_to_add = Bytes
+ }) ->
+ ssh_bits:encode([?SSH_MSG_CHANNEL_WINDOW_ADJUST, Recipient, Bytes],
+ [byte, uint32, uint32]);
+encode(#ssh_msg_channel_data{
+ recipient_channel = Recipient,
+ data = Data
+ }) ->
+ ssh_bits:encode([?SSH_MSG_CHANNEL_DATA, Recipient, Data], [byte, uint32, binary]);
+
+encode(#ssh_msg_channel_extended_data{
+ recipient_channel = Recipient,
+ data_type_code = DataType,
+ data = Data
+ }) ->
+ ssh_bits:encode([?SSH_MSG_CHANNEL_EXTENDED_DATA, Recipient,
+ DataType, Data], [byte, uint32, uint32, binary]);
+
+encode(#ssh_msg_channel_eof{recipient_channel = Recipient
+ }) ->
+ <<?BYTE(?SSH_MSG_CHANNEL_EOF), ?UINT32(Recipient)>>;
+encode(#ssh_msg_channel_close{
+ recipient_channel = Recipient
+ }) ->
+ <<?BYTE(?SSH_MSG_CHANNEL_CLOSE), ?UINT32(Recipient)>>;
+encode(#ssh_msg_channel_request{
+ recipient_channel = Recipient,
+ request_type = Type,
+ want_reply = Bool,
+ data = Data
+ }) ->
+ ssh_bits:encode([?SSH_MSG_CHANNEL_REQUEST, Recipient, Type, Bool, Data],
+ [byte, uint32, string, boolean, '...']);
+encode(#ssh_msg_channel_success{
+ recipient_channel = Recipient
+ }) ->
+ <<?BYTE(?SSH_MSG_CHANNEL_SUCCESS), ?UINT32(Recipient)>>;
+encode(#ssh_msg_channel_failure{
+ recipient_channel = Recipient
+ }) ->
+ <<?BYTE(?SSH_MSG_CHANNEL_FAILURE), ?UINT32(Recipient)>>;
+
+encode(#ssh_msg_userauth_request{
+ user = User,
+ service = Service,
+ method = Method,
+ data = Data
+ }) ->
+ ssh_bits:encode([?SSH_MSG_USERAUTH_REQUEST, User, Service, Method, Data],
+ [byte, string, string, string, '...']);
+encode(#ssh_msg_userauth_failure{
+ authentications = Auths,
+ partial_success = Bool
+ }) ->
+ ssh_bits:encode([?SSH_MSG_USERAUTH_FAILURE, Auths, Bool],
+ [byte, string, boolean]);
+encode(#ssh_msg_userauth_success{}) ->
+ <<?BYTE(?SSH_MSG_USERAUTH_SUCCESS)>>;
+
+encode(#ssh_msg_userauth_banner{
+ message = Banner,
+ language = Lang
+ }) ->
+ ssh_bits:encode([?SSH_MSG_USERAUTH_BANNER, Banner, Lang],
+ [byte, string, string]);
+
+encode(#ssh_msg_userauth_pk_ok{
+ algorithm_name = Alg,
+ key_blob = KeyBlob
+ }) ->
+ ssh_bits:encode([?SSH_MSG_USERAUTH_PK_OK, Alg, KeyBlob],
+ [byte, string, binary]);
+
+encode(#ssh_msg_userauth_passwd_changereq{prompt = Prompt,
+ languge = Lang
+ })->
+ ssh_bits:encode([?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ, Prompt, Lang],
+ [byte, string, string]);
+
+encode(#ssh_msg_userauth_info_request{
+ name = Name,
+ instruction = Inst,
+ language_tag = Lang,
+ num_prompts = NumPromtps,
+ data = Data}) ->
+ ssh_bits:encode([?SSH_MSG_USERAUTH_INFO_REQUEST, Name, Inst, Lang, NumPromtps, Data],
+ [byte, string, string, string, uint32, '...']);
+
+encode(#ssh_msg_userauth_info_response{
+ num_responses = Num,
+ data = Data}) ->
+ ssh_bits:encode([?SSH_MSG_USERAUTH_INFO_RESPONSE, Num, Data],
+ [byte, uint32, '...']);
+encode(#ssh_msg_disconnect{
+ code = Code,
+ description = Desc,
+ language = Lang
+ }) ->
+ ssh_bits:encode([?SSH_MSG_DISCONNECT, Code, Desc, Lang],
+ [byte, uint32, string, string]);
+
+encode(#ssh_msg_service_request{
+ name = Service
+ }) ->
+ ssh_bits:encode([?SSH_MSG_SERVICE_REQUEST, Service], [byte, string]);
+
+encode(#ssh_msg_service_accept{
+ name = Service
+ }) ->
+ ssh_bits:encode([?SSH_MSG_SERVICE_ACCEPT, Service], [byte, string]);
+
+encode(#ssh_msg_newkeys{}) ->
+ <<?BYTE(?SSH_MSG_NEWKEYS)>>;
+
+encode(#ssh_msg_kexinit{
+ cookie = Cookie,
+ kex_algorithms = KeyAlgs,
+ server_host_key_algorithms = HostKeyAlgs,
+ encryption_algorithms_client_to_server = EncAlgC2S,
+ encryption_algorithms_server_to_client = EncAlgS2C,
+ mac_algorithms_client_to_server = MacAlgC2S,
+ mac_algorithms_server_to_client = MacAlgS2C,
+ compression_algorithms_client_to_server = CompAlgS2C,
+ compression_algorithms_server_to_client = CompAlgC2S,
+ languages_client_to_server = LangC2S,
+ languages_server_to_client = LangS2C,
+ first_kex_packet_follows = Bool,
+ reserved = Reserved
+ }) ->
+ ssh_bits:encode([?SSH_MSG_KEXINIT, Cookie, KeyAlgs, HostKeyAlgs, EncAlgC2S, EncAlgS2C,
+ MacAlgC2S, MacAlgS2C, CompAlgS2C, CompAlgC2S, LangC2S, LangS2C, Bool,
+ Reserved],
+ [byte, cookie,
+ name_list, name_list,
+ name_list, name_list,
+ name_list, name_list,
+ name_list, name_list,
+ name_list, name_list,
+ boolean, uint32]);
+
+encode(#ssh_msg_kexdh_init{e = E}) ->
+ ssh_bits:encode([?SSH_MSG_KEXDH_INIT, E], [byte, mpint]);
+
+encode(#ssh_msg_kexdh_reply{
+ public_host_key = Key,
+ f = F,
+ h_sig = Signature
+ }) ->
+ EncKey = encode_host_key(Key),
+ EncSign = encode_sign(Key, Signature),
+ ssh_bits:encode([?SSH_MSG_KEXDH_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]);
+
+encode(#ssh_msg_kex_dh_gex_request{
+ min = Min,
+ n = N,
+ max = Max
+ }) ->
+ ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REQUEST, Min, N, Max],
+ [byte, uint32, uint32, uint32, uint32]);
+encode(#ssh_msg_kex_dh_gex_request_old{n = N}) ->
+ ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_REQUEST_OLD, N],
+ [byte, uint32]);
+
+encode(#ssh_msg_kex_dh_gex_group{p = Prime, g = Generator}) ->
+ ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_GROUP, Prime, Generator],
+ [byte, mpint, mpint]);
+
+encode(#ssh_msg_kex_dh_gex_init{e = Public}) ->
+ ssh_bits:encode([?SSH_MSG_KEX_DH_GEX_INIT, Public], [byte, mpint]);
+
+encode(#ssh_msg_kex_dh_gex_reply{
+ %% Will be private key encode_host_key extracts only the public part!
+ public_host_key = Key,
+ f = F,
+ h_sig = Signature
+ }) ->
+ EncKey = encode_host_key(Key),
+ EncSign = encode_sign(Key, Signature),
+ ssh_bits:encode([?SSH_MSG_KEXDH_REPLY, EncKey, F, EncSign], [byte, binary, mpint, binary]);
+
+encode(#ssh_msg_ignore{data = Data}) ->
+ ssh_bits:encode([?SSH_MSG_IGNORE, Data], [byte, string]);
+
+encode(#ssh_msg_unimplemented{sequence = Seq}) ->
+ ssh_bits:encode([?SSH_MSG_IGNORE, Seq], [byte, uint32]);
+
+encode(#ssh_msg_debug{always_display = Bool,
+ message = Msg,
+ language = Lang}) ->
+ ssh_bits:encode([?SSH_MSG_DEBUG, Bool, Msg, Lang], [byte, boolean, string, string]).
+
+
+%% Connection Messages
+decode(<<?BYTE(?SSH_MSG_GLOBAL_REQUEST), ?UINT32(Len), Name:Len/binary,
+ ?BYTE(Bool), Data/binary>>) ->
+ #ssh_msg_global_request{
+ name = Name,
+ want_reply = erl_boolean(Bool),
+ data = Data
+ };
+decode(<<?BYTE(?SSH_MSG_REQUEST_SUCCESS), Data/binary>>) ->
+ #ssh_msg_request_success{data = Data};
+decode(<<?BYTE(?SSH_MSG_REQUEST_FAILURE)>>) ->
+ #ssh_msg_request_failure{};
+decode(<<?BYTE(?SSH_MSG_CHANNEL_OPEN),
+ ?UINT32(Len), Type:Len/binary,
+ ?UINT32(Sender), ?UINT32(Window), ?UINT32(Max),
+ Data/binary>>) ->
+ #ssh_msg_channel_open{
+ channel_type = binary_to_list(Type),
+ sender_channel = Sender,
+ initial_window_size = Window,
+ maximum_packet_size = Max,
+ data = Data
+ };
+decode(<<?BYTE(?SSH_MSG_CHANNEL_OPEN_CONFIRMATION), ?UINT32(Recipient), ?UINT32(Sender),
+ ?UINT32(InitWindowSize), ?UINT32(MaxPacketSize),
+ Data/binary>>) ->
+ #ssh_msg_channel_open_confirmation{
+ recipient_channel = Recipient,
+ sender_channel = Sender,
+ initial_window_size = InitWindowSize,
+ maximum_packet_size = MaxPacketSize,
+ data = Data
+ };
+decode(<<?BYTE(?SSH_MSG_CHANNEL_OPEN_FAILURE), ?UINT32(Recipient), ?UINT32(Reason),
+ ?UINT32(Len0), Desc:Len0/binary, ?UINT32(Len1), Lang:Len1/binary >>) ->
+ #ssh_msg_channel_open_failure{
+ recipient_channel = Recipient,
+ reason = Reason,
+ description = unicode:characters_to_list(Desc),
+ lang = Lang
+ };
+decode(<<?BYTE(?SSH_MSG_CHANNEL_WINDOW_ADJUST), ?UINT32(Recipient), ?UINT32(Bytes)>>) ->
+ #ssh_msg_channel_window_adjust{
+ recipient_channel = Recipient,
+ bytes_to_add = Bytes
+ };
+
+decode(<<?BYTE(?SSH_MSG_CHANNEL_DATA), ?UINT32(Recipient), ?UINT32(Len), Data:Len/binary>>) ->
+ #ssh_msg_channel_data{
+ recipient_channel = Recipient,
+ data = Data
+ };
+decode(<<?BYTE(?SSH_MSG_CHANNEL_EXTENDED_DATA), ?UINT32(Recipient),
+ ?UINT32(DataType), Data/binary>>) ->
+ #ssh_msg_channel_extended_data{
+ recipient_channel = Recipient,
+ data_type_code = DataType,
+ data = Data
+ };
+decode(<<?BYTE(?SSH_MSG_CHANNEL_EOF), ?UINT32(Recipient)>>) ->
+ #ssh_msg_channel_eof{
+ recipient_channel = Recipient
+ };
+decode(<<?BYTE(?SSH_MSG_CHANNEL_CLOSE), ?UINT32(Recipient)>>) ->
+ #ssh_msg_channel_close{
+ recipient_channel = Recipient
+ };
+decode(<<?BYTE(?SSH_MSG_CHANNEL_REQUEST), ?UINT32(Recipient),
+ ?UINT32(Len), RequestType:Len/binary,
+ ?BYTE(Bool), Data/binary>>) ->
+ #ssh_msg_channel_request{
+ recipient_channel = Recipient,
+ request_type = unicode:characters_to_list(RequestType),
+ want_reply = erl_boolean(Bool),
+ data = Data
+ };
+decode(<<?BYTE(?SSH_MSG_CHANNEL_SUCCESS), ?UINT32(Recipient)>>) ->
+ #ssh_msg_channel_success{
+ recipient_channel = Recipient
+ };
+decode(<<?BYTE(?SSH_MSG_CHANNEL_FAILURE), ?UINT32(Recipient)>>) ->
+ #ssh_msg_channel_failure{
+ recipient_channel = Recipient
+ };
+
+%%% Auth Messages
+decode(<<?BYTE(?SSH_MSG_USERAUTH_REQUEST),
+ ?UINT32(Len0), User:Len0/binary,
+ ?UINT32(Len1), Service:Len1/binary,
+ ?UINT32(Len2), Method:Len2/binary,
+ Data/binary>>) ->
+ #ssh_msg_userauth_request{
+ user = unicode:characters_to_list(User),
+ service = unicode:characters_to_list(Service),
+ method = unicode:characters_to_list(Method),
+ data = Data
+ };
+
+decode(<<?BYTE(?SSH_MSG_USERAUTH_FAILURE),
+ ?UINT32(Len0), Auths:Len0/binary,
+ ?BYTE(Bool)>>) ->
+ #ssh_msg_userauth_failure {
+ authentications = unicode:characters_to_list(Auths),
+ partial_success = erl_boolean(Bool)
+ };
+
+decode(<<?BYTE(?SSH_MSG_USERAUTH_SUCCESS)>>) ->
+ #ssh_msg_userauth_success{};
+
+decode(<<?BYTE(?SSH_MSG_USERAUTH_BANNER),
+ ?UINT32(Len0), Banner:Len0/binary,
+ ?UINT32(Len1), Lang:Len1/binary>>) ->
+ #ssh_msg_userauth_banner{
+ message = Banner,
+ language = Lang
+ };
+
+decode(<<?BYTE(?SSH_MSG_USERAUTH_PK_OK), ?UINT32(Len), Alg:Len/binary, KeyBlob/binary>>) ->
+ #ssh_msg_userauth_pk_ok{
+ algorithm_name = Alg,
+ key_blob = KeyBlob
+ };
+
+decode(<<?BYTE(?SSH_MSG_USERAUTH_PASSWD_CHANGEREQ), ?UINT32(Len0), Prompt:Len0/binary,
+ ?UINT32(Len1), Lang:Len1/binary>>) ->
+ #ssh_msg_userauth_passwd_changereq{
+ prompt = Prompt,
+ languge = Lang
+ };
+decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_REQUEST), ?UINT32(Len0), Name:Len0/binary,
+ ?UINT32(Len1), Inst:Len1/binary, ?UINT32(Len2), Lang:Len2/binary,
+ ?UINT32(NumPromtps), Data/binary>>) ->
+ #ssh_msg_userauth_info_request{
+ name = Name,
+ instruction = Inst,
+ language_tag = Lang,
+ num_prompts = NumPromtps,
+ data = Data};
+
+decode(<<?BYTE(?SSH_MSG_USERAUTH_INFO_RESPONSE), ?UINT32(Num), Data/binary>>) ->
+ #ssh_msg_userauth_info_response{
+ num_responses = Num,
+ data = Data};
+
+%%% Keyexchange messages
+decode(<<?BYTE(?SSH_MSG_KEXINIT), Cookie:128, Data/binary>>) ->
+ decode_kex_init(Data, [Cookie, ssh_msg_kexinit], 10);
+
+decode(<<?BYTE(?SSH_MSG_KEXDH_INIT), ?UINT32(Len), E:Len/binary>>) ->
+ #ssh_msg_kexdh_init{e = erlint(Len, E)
+ };
+decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST), ?UINT32(Min), ?UINT32(N), ?UINT32(Max)>>) ->
+ #ssh_msg_kex_dh_gex_request{
+ min = Min,
+ n = N,
+ max = Max
+ };
+decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_REQUEST_OLD), ?UINT32(N)>>) ->
+ #ssh_msg_kex_dh_gex_request_old{
+ n = N
+ };
+decode(<<?BYTE(?SSH_MSG_KEX_DH_GEX_GROUP), ?UINT32(Len0), Prime:Len0/big-signed-integer,
+ ?UINT32(Len1), Generator:Len1/big-signed-integer>>) ->
+ #ssh_msg_kex_dh_gex_group{
+ p = Prime,
+ g = Generator
+ };
+decode(<<?BYTE(?SSH_MSG_KEXDH_REPLY), ?UINT32(Len0), Key:Len0/binary,
+ ?UINT32(Len1), F:Len1/binary,
+ ?UINT32(Len2), Hashsign:Len2/binary>>) ->
+ #ssh_msg_kexdh_reply{
+ public_host_key = decode_host_key(Key),
+ f = erlint(Len1, F),
+ h_sig = decode_sign(Hashsign)
+ };
+
+decode(<<?SSH_MSG_SERVICE_REQUEST, ?UINT32(Len0), Service:Len0/binary>>) ->
+ #ssh_msg_service_request{
+ name = unicode:characters_to_list(Service)
+ };
+
+decode(<<?SSH_MSG_SERVICE_ACCEPT, ?UINT32(Len0), Service:Len0/binary>>) ->
+ #ssh_msg_service_accept{
+ name = unicode:characters_to_list(Service)
+ };
+
+decode(<<?BYTE(?SSH_MSG_DISCONNECT), ?UINT32(Code),
+ ?UINT32(Len0), Desc:Len0/binary, ?UINT32(Len1), Lang:Len1/binary>>) ->
+ #ssh_msg_disconnect{
+ code = Code,
+ description = unicode:characters_to_list(Desc),
+ language = Lang
+ };
+
+decode(<<?SSH_MSG_NEWKEYS>>) ->
+ #ssh_msg_newkeys{};
+
+decode(<<?BYTE(?SSH_MSG_IGNORE), Data/binary>>) ->
+ #ssh_msg_ignore{data = Data};
+
+decode(<<?BYTE(?SSH_MSG_UNIMPLEMENTED), ?UINT32(Seq)>>) ->
+ #ssh_msg_unimplemented{sequence = Seq};
+
+decode(<<?BYTE(?SSH_MSG_DEBUG), ?BYTE(Bool), ?UINT32(Len0), Msg:Len0/binary,
+ ?UINT32(Len1), Lang:Len1/binary>>) ->
+ #ssh_msg_debug{always_display = erl_boolean(Bool),
+ message = Msg,
+ language = Lang}.
+
+decode_keyboard_interactive_prompts(<<>>, Acc) ->
+ lists:reverse(Acc);
+decode_keyboard_interactive_prompts(<<?UINT32(Len), Prompt:Len/binary, ?BYTE(Bool), Bin/binary>>,
+ Acc) ->
+ decode_keyboard_interactive_prompts(Bin, [{Prompt, erl_boolean(Bool)} | Acc]).
+
+erl_boolean(0) ->
+ false;
+erl_boolean(1) ->
+ true.
+
+decode_kex_init(<<?BYTE(Bool), ?UINT32(X)>>, Acc, 0) ->
+ list_to_tuple(lists:reverse([X, erl_boolean(Bool) | Acc]));
+decode_kex_init(<<?UINT32(Len), Data:Len/binary, Rest/binary>>, Acc, N) ->
+ Names = string:tokens(unicode:characters_to_list(Data), ","),
+ decode_kex_init(Rest, [Names | Acc], N -1).
+
+erlint(MPIntSize, MPIntValue) ->
+ Bits = MPIntSize * 8,
+ <<Integer:Bits/integer>> = MPIntValue,
+ Integer.
+
+decode_sign(<<?UINT32(Len), _Alg:Len/binary, ?UINT32(_), Signature/binary>>) ->
+ Signature.
+
+decode_host_key(<<?UINT32(Len), Alg:Len/binary, Rest/binary>>) ->
+ decode_host_key(Alg, Rest).
+
+decode_host_key(<<"ssh-rsa">>, <<?UINT32(Len0), E:Len0/binary,
+ ?UINT32(Len1), N:Len1/binary>>) ->
+ #'RSAPublicKey'{publicExponent = erlint(Len0, E),
+ modulus = erlint(Len1, N)};
+
+decode_host_key(<<"ssh-dss">>,
+ <<?UINT32(Len0), P:Len0/binary,
+ ?UINT32(Len1), Q:Len1/binary,
+ ?UINT32(Len2), G:Len2/binary,
+ ?UINT32(Len3), Y:Len3/binary>>) ->
+ {erlint(Len3, Y), #'Dss-Parms'{p = erlint(Len0, P), q = erlint(Len1, Q),
+ g = erlint(Len2, G)}}.
+
+encode_host_key(#'RSAPublicKey'{modulus = N, publicExponent = E}) ->
+ ssh_bits:encode(["ssh-rsa", E, N], [string, mpint, mpint]);
+encode_host_key({Y, #'Dss-Parms'{p = P, q = Q, g = G}}) ->
+ ssh_bits:encode(["ssh-dss", P, Q, G, Y],
+ [string, mpint, mpint, mpint, mpint]);
+encode_host_key(#'RSAPrivateKey'{modulus = N, publicExponent = E}) ->
+ ssh_bits:encode(["ssh-rsa", E, N], [string, mpint, mpint]);
+encode_host_key(#'DSAPrivateKey'{y = Y, p = P, q = Q, g = G}) ->
+ ssh_bits:encode(["ssh-dss", P, Q, G, Y],
+ [string, mpint, mpint, mpint, mpint]).
+encode_sign(#'RSAPrivateKey'{}, Signature) ->
+ ssh_bits:encode(["ssh-rsa", Signature],[string, binary]);
+encode_sign(#'DSAPrivateKey'{}, Signature) ->
+ ssh_bits:encode(["ssh-dss", Signature],[string, binary]).
diff --git a/lib/ssh/src/ssh_no_io.erl b/lib/ssh/src/ssh_no_io.erl
index 2c8dd92ee2..9f83506cdd 100644
--- a/lib/ssh/src/ssh_no_io.erl
+++ b/lib/ssh/src/ssh_no_io.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,18 +22,31 @@
%%% Description: ssh_io replacement that throws on everything
-module(ssh_no_io).
+-include("ssh_transport.hrl").
-export([yes_no/1, read_password/1, read_line/1, format/2]).
yes_no(_Prompt) ->
- throw({no_io_allowed, yes_no}).
+ throw({{no_io_allowed, yes_no},
+ #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
+ description = "User interaction is not allowed",
+ language = "en"}}).
read_password(_Prompt) ->
- throw({no_io_allowed, read_password}).
+ throw({{no_io_allowed, read_password},
+ #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
+ description = "User interaction is not allowed",
+ language = "en"}}).
read_line(_Prompt) ->
- throw({no_io_allowed, read_line}).
+ throw({{no_io_allowed, read_line},
+ #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
+ description = "User interaction is not allowed",
+ language = "en"}} ).
format(_Fmt, _Args) ->
- throw({no_io_allowed, format}).
+ throw({{no_io_allowed, format},
+ #ssh_msg_disconnect{code = ?SSH_DISCONNECT_SERVICE_NOT_AVAILABLE,
+ description = "User interaction is not allowed",
+ language = "en"}}).
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index 3d469d3c6e..174ca0126b 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -76,7 +76,7 @@ listen(Addr, Port, Options) ->
%% Description: Stops the listener
%%--------------------------------------------------------------------
stop(Pid) ->
- ssh_cli:stop(Pid).
+ ssh:stop_listener(Pid).
%%% DEPRECATED END %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/ssh/src/ssh_subsystem_sup.erl b/lib/ssh/src/ssh_subsystem_sup.erl
index cd6defd535..e8855b09ac 100644
--- a/lib/ssh/src/ssh_subsystem_sup.erl
+++ b/lib/ssh/src/ssh_subsystem_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -25,7 +25,9 @@
-behaviour(supervisor).
--export([start_link/1, connection_supervisor/1, channel_supervisor/1
+-export([start_link/1,
+ connection_supervisor/1,
+ channel_supervisor/1
]).
%% Supervisor callback
@@ -61,9 +63,9 @@ init([Opts]) ->
child_specs(Opts) ->
case proplists:get_value(role, Opts) of
client ->
- [ssh_connectinon_child_spec(Opts)];
+ [];
server ->
- [ssh_connectinon_child_spec(Opts), ssh_channel_child_spec(Opts)]
+ [ssh_channel_child_spec(Opts), ssh_connectinon_child_spec(Opts)]
end.
ssh_connectinon_child_spec(Opts) ->
@@ -72,9 +74,9 @@ ssh_connectinon_child_spec(Opts) ->
Role = proplists:get_value(role, Opts),
Name = id(Role, ssh_connection_sup, Address, Port),
StartFunc = {ssh_connection_sup, start_link, [Opts]},
- Restart = transient,
+ Restart = temporary,
Shutdown = 5000,
- Modules = [ssh_connection_sup],
+ Modules = [ssh_connection_sup],
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
@@ -84,7 +86,7 @@ ssh_channel_child_spec(Opts) ->
Role = proplists:get_value(role, Opts),
Name = id(Role, ssh_channel_sup, Address, Port),
StartFunc = {ssh_channel_sup, start_link, [Opts]},
- Restart = transient,
+ Restart = temporary,
Shutdown = infinity,
Modules = [ssh_channel_sup],
Type = supervisor,
diff --git a/lib/ssh/src/ssh_sup.erl b/lib/ssh/src/ssh_sup.erl
index f307d1f833..6d2b9c107d 100644
--- a/lib/ssh/src/ssh_sup.erl
+++ b/lib/ssh/src/ssh_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -51,8 +51,7 @@ children() ->
Clients = [Service || Service <- Services, is_client(Service)],
Servers = [Service || Service <- Services, is_server(Service)],
- [server_child_spec(Servers), client_child_spec(Clients),
- ssh_userauth_reg_spec()].
+ [server_child_spec(Servers), client_child_spec(Clients)].
server_child_spec(Servers) ->
Name = sshd_sup,
@@ -72,16 +71,6 @@ client_child_spec(Clients) ->
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-ssh_userauth_reg_spec() ->
- Name = ssh_userreg,
- StartFunc = {ssh_userreg, start_link, []},
- Restart = transient,
- Shutdown = 5000,
- Modules = [ssh_userreg],
- Type = worker,
- {Name, StartFunc, Restart, Shutdown, Type, Modules}.
-
-
is_server({sftpd, _}) ->
true;
is_server({shelld, _}) ->
diff --git a/lib/ssh/src/ssh_system_sup.erl b/lib/ssh/src/ssh_system_sup.erl
index 36daf3b1ac..bf3c12a988 100644
--- a/lib/ssh/src/ssh_system_sup.erl
+++ b/lib/ssh/src/ssh_system_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -40,7 +40,7 @@
-export([init/1]).
%%%=========================================================================
-%%% API
+%%% Internal API
%%%=========================================================================
start_link(ServerOpts) ->
Address = proplists:get_value(address, ServerOpts),
@@ -55,13 +55,12 @@ stop_listener(Address, Port) ->
Name = make_name(Address, Port),
stop_acceptor(whereis(Name)).
-stop_system(SysSup) ->
- Name = sshd_sup:system_name(SysSup),
- sshd_sup:stop_child(Name).
-
-stop_system(Address, Port) ->
- sshd_sup:stop_child(Address, Port).
+stop_system(SysSup) when is_pid(SysSup)->
+ exit(SysSup, shutdown).
+stop_system(Address, Port) ->
+ stop_system(system_supervisor(Address, Port)).
+
system_supervisor(Address, Port) ->
Name = make_name(Address, Port),
whereis(Name).
@@ -121,7 +120,7 @@ restart_acceptor(Address, Port) ->
%%%=========================================================================
init([ServerOpts]) ->
RestartStrategy = one_for_one,
- MaxR = 10,
+ MaxR = 0,
MaxT = 3600,
Children = child_specs(ServerOpts),
{ok, {{RestartStrategy, MaxR, MaxT}, Children}}.
@@ -146,7 +145,7 @@ ssh_acceptor_child_spec(ServerOpts) ->
ssh_subsystem_child_spec(ServerOpts) ->
Name = make_ref(),
StartFunc = {ssh_subsystem_sup, start_link, [ServerOpts]},
- Restart = transient,
+ Restart = temporary,
Shutdown = infinity,
Modules = [ssh_subsystem_sup],
Type = supervisor,
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index 682d766d99..27723dc870 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -29,12 +29,12 @@
-include("ssh_transport.hrl").
-include("ssh.hrl").
--export([connect/5, accept/4]).
-export([versions/2, hello_version_msg/1]).
-export([next_seqnum/1, decrypt_first_block/2, decrypt_blocks/3,
- is_valid_mac/3, transport_messages/1, kexdh_messages/0,
- kex_dh_gex_messages/0, handle_hello_version/1,
- key_exchange_init_msg/1, key_init/3, new_keys_message/1,
+ is_valid_mac/3,
+ handle_hello_version/1,
+ key_exchange_init_msg/1,
+ key_init/3, new_keys_message/1,
handle_kexinit_msg/3, handle_kexdh_init/2,
handle_kex_dh_gex_group/2, handle_kex_dh_gex_reply/2,
handle_new_keys/2, handle_kex_dh_gex_request/2,
@@ -74,113 +74,9 @@ is_valid_mac(Mac, Data, #ssh{recv_mac = Algorithm,
recv_mac_key = Key, recv_sequence = SeqNum}) ->
Mac == mac(Algorithm, Key, SeqNum, Data).
-transport_messages(_) ->
- [{ssh_msg_disconnect, ?SSH_MSG_DISCONNECT,
- [uint32, string, string]},
-
- {ssh_msg_ignore, ?SSH_MSG_IGNORE,
- [string]},
-
- {ssh_msg_unimplemented, ?SSH_MSG_UNIMPLEMENTED,
- [uint32]},
-
- {ssh_msg_debug, ?SSH_MSG_DEBUG,
- [boolean, string, string]},
-
- {ssh_msg_service_request, ?SSH_MSG_SERVICE_REQUEST,
- [string]},
-
- {ssh_msg_service_accept, ?SSH_MSG_SERVICE_ACCEPT,
- [string]},
-
- {ssh_msg_kexinit, ?SSH_MSG_KEXINIT,
- [cookie,
- name_list, name_list,
- name_list, name_list,
- name_list, name_list,
- name_list, name_list,
- name_list, name_list,
- boolean,
- uint32]},
-
- {ssh_msg_newkeys, ?SSH_MSG_NEWKEYS,
- []}
- ].
-
-kexdh_messages() ->
- [{ssh_msg_kexdh_init, ?SSH_MSG_KEXDH_INIT,
- [mpint]},
-
- {ssh_msg_kexdh_reply, ?SSH_MSG_KEXDH_REPLY,
- [binary, mpint, binary]}
- ].
-
-kex_dh_gex_messages() ->
- [{ssh_msg_kex_dh_gex_request, ?SSH_MSG_KEX_DH_GEX_REQUEST,
- [uint32, uint32, uint32]},
-
- {ssh_msg_kex_dh_gex_request_old, ?SSH_MSG_KEX_DH_GEX_REQUEST_OLD,
- [uint32]},
-
- {ssh_msg_kex_dh_gex_group, ?SSH_MSG_KEX_DH_GEX_GROUP,
- [mpint, mpint]},
-
- {ssh_msg_kex_dh_gex_init, ?SSH_MSG_KEX_DH_GEX_INIT,
- [mpint]},
-
- {ssh_msg_kex_dh_gex_reply, ?SSH_MSG_KEX_DH_GEX_REPLY,
- [binary, mpint, binary]}
- ].
-
yes_no(Ssh, Prompt) ->
(Ssh#ssh.io_cb):yes_no(Prompt, Ssh).
-connect(ConnectionSup, Address, Port, SocketOpts, Opts) ->
- Timeout = proplists:get_value(connect_timeout, Opts, infinity),
- {_, Callback, _} =
- proplists:get_value(transport, Opts, {tcp, gen_tcp, tcp_closed}),
- case do_connect(Callback, Address, Port, SocketOpts, Timeout) of
- {ok, Socket} ->
- {ok, Pid} =
- ssh_connection_sup:start_handler_child(ConnectionSup,
- [client, Socket,
- [{address, Address},
- {port, Port} |
- Opts]]),
- Callback:controlling_process(Socket, Pid),
- ssh_connection_handler:send_event(Pid, socket_control),
- {ok, Pid};
- {error, Reason} ->
- {error, Reason}
- end.
-
-do_connect(Callback, Address, Port, SocketOpts, Timeout) ->
- Opts = [{active, false} | SocketOpts],
- case Callback:connect(Address, Port, Opts, Timeout) of
- {error, nxdomain} ->
- Callback:connect(Address, Port, lists:delete(inet6, Opts), Timeout);
- {error, eafnosupport} ->
- Callback:connect(Address, Port, lists:delete(inet6, Opts), Timeout);
- {error, enetunreach} ->
- Callback:connect(Address, Port, lists:delete(inet6, Opts), Timeout);
- Other ->
- Other
- end.
-
-accept(Address, Port, Socket, Options) ->
- {_, Callback, _} =
- proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}),
- ConnectionSup =
- ssh_system_sup:connection_supervisor(
- ssh_system_sup:system_supervisor(Address, Port)),
- {ok, Pid} =
- ssh_connection_sup:start_handler_child(ConnectionSup,
- [server, Socket,
- [{address, Address},
- {port, Port} | Options]]),
- Callback:controlling_process(Socket, Pid),
- {ok, Pid}.
-
format_version({Major,Minor}) ->
"SSH-" ++ integer_to_list(Major) ++ "." ++
integer_to_list(Minor) ++ "-Erlang".
@@ -257,7 +153,6 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
{ok, Algoritms} = select_algorithm(client, Own, CounterPart),
case verify_algorithm(Algoritms) of
true ->
- install_messages(Algoritms#alg.kex),
key_exchange_first_msg(Algoritms#alg.kex,
Ssh0#ssh{algorithms = Algoritms});
_ ->
@@ -271,7 +166,6 @@ handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
handle_kexinit_msg(#ssh_msg_kexinit{} = CounterPart, #ssh_msg_kexinit{} = Own,
#ssh{role = server} = Ssh) ->
{ok, Algoritms} = select_algorithm(server, CounterPart, Own),
- install_messages(Algoritms#alg.kex),
{ok, Ssh#ssh{algorithms = Algoritms}}.
@@ -284,11 +178,6 @@ verify_algorithm(#alg{kex = 'diffie-hellman-group-exchange-sha1'}) ->
verify_algorithm(_) ->
false.
-install_messages('diffie-hellman-group1-sha1') ->
- ssh_bits:install_messages(kexdh_messages());
-install_messages('diffie-hellman-group-exchange-sha1') ->
- ssh_bits:install_messages(kex_dh_gex_messages()).
-
key_exchange_first_msg('diffie-hellman-group1-sha1', Ssh0) ->
{G, P} = dh_group1(),
{Private, Public} = dh_gen_key(G, P, 1024),
@@ -312,10 +201,10 @@ handle_kexdh_init(#ssh_msg_kexdh_init{e = E}, Ssh0) ->
{G, P} = dh_group1(),
{Private, Public} = dh_gen_key(G, P, 1024),
K = ssh_math:ipow(E, Private, P),
- {Key, K_S} = get_host_key(Ssh0),
- H = kex_h(Ssh0, K_S, E, Public, K),
+ Key = get_host_key(Ssh0),
+ H = kex_h(Ssh0, Key, E, Public, K),
H_SIG = sign_host_key(Ssh0, Key, H),
- {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_reply{public_host_key = K_S,
+ {SshPacket, Ssh1} = ssh_packet(#ssh_msg_kexdh_reply{public_host_key = Key,
f = Public,
h_sig = H_SIG
}, Ssh0),
@@ -411,65 +300,33 @@ get_host_key(SSH) ->
#ssh{key_cb = Mod, opts = Opts, algorithms = ALG} = SSH,
case Mod:host_key(ALG#alg.hkey, Opts) of
- {ok, #'RSAPrivateKey'{modulus = N, publicExponent = E} = Key} ->
- {Key,
- ssh_bits:encode(["ssh-rsa",E,N],[string,mpint,mpint])};
- {ok, #'DSAPrivateKey'{y = Y, p = P, q = Q, g = G} = Key} ->
- {Key, ssh_bits:encode(["ssh-dss",P,Q,G,Y],
- [string,mpint,mpint,mpint,mpint])};
+ {ok, #'RSAPrivateKey'{} = Key} ->
+ Key;
+ {ok, #'DSAPrivateKey'{} = Key} ->
+ Key;
Result ->
exit({error, {Result, unsupported_key_type}})
end.
sign_host_key(_Ssh, #'RSAPrivateKey'{} = Private, H) ->
Hash = sha, %% Option ?!
- Signature = sign(H, Hash, Private),
- ssh_bits:encode(["ssh-rsa", Signature],[string, binary]);
+ _Signature = sign(H, Hash, Private);
sign_host_key(_Ssh, #'DSAPrivateKey'{} = Private, H) ->
Hash = sha, %% Option ?!
- RawSignature = sign(H, Hash, Private),
- ssh_bits:encode(["ssh-dss", RawSignature],[string, binary]).
+ _RawSignature = sign(H, Hash, Private).
-verify_host_key(SSH, K_S, H, H_SIG) ->
- ALG = SSH#ssh.algorithms,
- case ALG#alg.hkey of
- 'ssh-rsa' ->
- verify_host_key_rsa(SSH, K_S, H, H_SIG);
- 'ssh-dss' ->
- verify_host_key_dss(SSH, K_S, H, H_SIG);
- _ ->
- {error, bad_host_key_algorithm}
- end.
-
-verify_host_key_rsa(SSH, K_S, H, H_SIG) ->
- case ssh_bits:decode(K_S,[string,mpint,mpint]) of
- ["ssh-rsa", E, N] ->
- ["ssh-rsa",SIG] = ssh_bits:decode(H_SIG,[string,binary]),
- Public = #'RSAPublicKey'{publicExponent = E, modulus = N},
- case verify(H, sha, SIG, Public) of
- false ->
- {error, bad_signature};
- true ->
- known_host_key(SSH, Public, 'ssh-rsa')
- end;
- _ ->
- {error, bad_format}
+verify_host_key(SSH, PublicKey, Digest, Signature) ->
+ case verify(Digest, sha, Signature, PublicKey) of
+ false ->
+ {error, bad_signature};
+ true ->
+ known_host_key(SSH, PublicKey, public_algo(PublicKey))
end.
-verify_host_key_dss(SSH, K_S, H, H_SIG) ->
- case ssh_bits:decode(K_S,[string,mpint,mpint,mpint,mpint]) of
- ["ssh-dss",P,Q,G,Y] ->
- ["ssh-dss",SIG] = ssh_bits:decode(H_SIG,[string,binary]),
- Public = {Y, #'Dss-Parms'{p = P, q = Q, g = G}},
- case verify(H, sha, SIG, Public) of
- false ->
- {error, bad_signature};
- true ->
- known_host_key(SSH, Public, 'ssh-dss')
- end;
- _ ->
- {error, bad_host_key_format}
- end.
+public_algo(#'RSAPublicKey'{}) ->
+ 'ssh-rsa';
+public_algo({_, #'Dss-Parms'{}}) ->
+ 'ssh-dss'.
accepted_host(Ssh, PeerName, Opts) ->
case proplists:get_value(silently_accept_hosts, Opts, false) of
@@ -636,12 +493,12 @@ select(CL, SL) ->
C.
ssh_packet(#ssh_msg_kexinit{} = Msg, Ssh0) ->
- BinMsg = ssh_bits:encode(Msg),
+ BinMsg = ssh_message:encode(Msg),
Ssh = key_init(Ssh0#ssh.role, Ssh0, BinMsg),
pack(BinMsg, Ssh);
ssh_packet(Msg, Ssh) ->
- BinMsg = ssh_bits:encode(Msg),
+ BinMsg = ssh_message:encode(Msg),
pack(BinMsg, Ssh).
pack(Data0, #ssh{encrypt_block_size = BlockSize,
@@ -1021,23 +878,23 @@ hash(K, H, Ki, N, HASH) ->
Kj = HASH([K, H, Ki]),
hash(K, H, <<Ki/binary, Kj/binary>>, N-128, HASH).
-kex_h(SSH, K_S, E, F, K) ->
+kex_h(SSH, Key, E, F, K) ->
L = ssh_bits:encode([SSH#ssh.c_version, SSH#ssh.s_version,
SSH#ssh.c_keyinit, SSH#ssh.s_keyinit,
- K_S, E,F,K],
+ ssh_message:encode_host_key(Key), E,F,K],
[string,string,binary,binary,binary,
mpint,mpint,mpint]),
crypto:hash(sha,L).
-kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) ->
+kex_h(SSH, Key, Min, NBits, Max, Prime, Gen, E, F, K) ->
L = if Min==-1; Max==-1 ->
Ts = [string,string,binary,binary,binary,
uint32,
mpint,mpint,mpint,mpint,mpint],
ssh_bits:encode([SSH#ssh.c_version,SSH#ssh.s_version,
SSH#ssh.c_keyinit,SSH#ssh.s_keyinit,
- K_S, NBits, Prime, Gen, E,F,K],
+ ssh_message:encode_host_key(Key), NBits, Prime, Gen, E,F,K],
Ts);
true ->
Ts = [string,string,binary,binary,binary,
@@ -1045,7 +902,7 @@ kex_h(SSH, K_S, Min, NBits, Max, Prime, Gen, E, F, K) ->
mpint,mpint,mpint,mpint,mpint],
ssh_bits:encode([SSH#ssh.c_version,SSH#ssh.s_version,
SSH#ssh.c_keyinit,SSH#ssh.s_keyinit,
- K_S, Min, NBits, Max,
+ ssh_message:encode_host_key(Key), Min, NBits, Max,
Prime, Gen, E,F,K], Ts)
end,
crypto:hash(sha,L).
diff --git a/lib/ssh/src/ssh_userreg.erl b/lib/ssh/src/ssh_userreg.erl
deleted file mode 100644
index f901461aea..0000000000
--- a/lib/ssh/src/ssh_userreg.erl
+++ /dev/null
@@ -1,141 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2008-2011. 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%
-%%
-
-%%
-%% Description: User register for ssh_cli
-
--module(ssh_userreg).
-
--behaviour(gen_server).
-
-%% API
--export([start_link/0,
- register_user/2,
- lookup_user/1,
- delete_user/1]).
-
-%% gen_server callbacks
--export([init/1,
- handle_call/3,
- handle_cast/2,
- handle_info/2,
- terminate/2,
- code_change/3]).
-
--record(state, {user_db = []}).
-
-%%====================================================================
-%% API
-%%====================================================================
-%%--------------------------------------------------------------------
-%% Function: start_link() -> {ok,Pid} | ignore | {error,Error}
-%% Description: Starts the server
-%%--------------------------------------------------------------------
-start_link() ->
- gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
-
-register_user(User, Cm) ->
- gen_server:cast(?MODULE, {register, {User, Cm}}).
-
-delete_user(Cm) ->
- gen_server:cast(?MODULE, {delete, Cm}).
-
-lookup_user(Cm) ->
- gen_server:call(?MODULE, {get_user, Cm}, infinity).
-
-%%====================================================================
-%% gen_server callbacks
-%%====================================================================
-
-%%--------------------------------------------------------------------
-%% Function: init(Args) -> {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%% Description: Initiates the server
-%%--------------------------------------------------------------------
-init([]) ->
- {ok, #state{}}.
-
-%%--------------------------------------------------------------------
-%% Function: %% handle_call(Request, From, State) -> {reply, Reply, State} |
-%% {reply, Reply, State, Timeout} |
-%% {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, Reply, State} |
-%% {stop, Reason, State}
-%% Description: Handling call messages
-%%--------------------------------------------------------------------
-handle_call({get_user, Cm}, _From, #state{user_db = Db} = State) ->
- User = lookup(Cm, Db),
- {reply, {ok, User}, State}.
-
-%%--------------------------------------------------------------------
-%% Function: handle_cast(Msg, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
-%% Description: Handling cast messages
-%%--------------------------------------------------------------------
-handle_cast({register, UserCm}, State) ->
- {noreply, insert(UserCm, State)};
-handle_cast({delete, UserCm}, State) ->
- {noreply, delete(UserCm, State)}.
-
-%%--------------------------------------------------------------------
-%% Function: handle_info(Info, State) -> {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State}
-%% Description: Handling all non call/cast messages
-%%--------------------------------------------------------------------
-handle_info(_Info, State) ->
- {noreply, State}.
-
-%%--------------------------------------------------------------------
-%% Function: terminate(Reason, State) -> void()
-%% Description: This function is called by a gen_server when it is about to
-%% terminate. It should be the opposite of Module:init/1 and do any necessary
-%% cleaning up. When it returns, the gen_server terminates with Reason.
-%% The return value is ignored.
-%%--------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%--------------------------------------------------------------------
-%% Func: code_change(OldVsn, State, Extra) -> {ok, NewState}
-%% Description: Convert process state when code is changed
-%%--------------------------------------------------------------------
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%--------------------------------------------------------------------
-%%% Internal functions
-%%--------------------------------------------------------------------
-insert({User, Cm}, #state{user_db = Db} = State) ->
- State#state{user_db = [{User, Cm} | Db]}.
-
-delete(Cm, #state{user_db = Db} = State) ->
- State#state{user_db = lists:keydelete(Cm, 2, Db)}.
-
-lookup(_, []) ->
- undefined;
-lookup(Cm, [{User, Cm} | _Rest]) ->
- User;
-lookup(Cm, [_ | Rest]) ->
- lookup(Cm, Rest).
-
diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl
index b299868d41..e18e18a9a9 100644
--- a/lib/ssh/src/ssh_xfer.erl
+++ b/lib/ssh/src/ssh_xfer.erl
@@ -267,7 +267,7 @@ xf_request(XF, Op, Arg) ->
list_to_binary(Arg)
end,
Size = 1+size(Data),
- ssh_connection:send(CM, Channel, <<?UINT32(Size), Op, Data/binary>>).
+ ssh_connection:send(CM, Channel, [<<?UINT32(Size), Op, Data/binary>>]).
xf_send_reply(#ssh_xfer{cm = CM, channel = Channel}, Op, Arg) ->
Data = if
@@ -277,7 +277,7 @@ xf_send_reply(#ssh_xfer{cm = CM, channel = Channel}, Op, Arg) ->
list_to_binary(Arg)
end,
Size = 1 + size(Data),
- ssh_connection:send(CM, Channel, <<?UINT32(Size), Op, Data/binary>>).
+ ssh_connection:send(CM, Channel, [<<?UINT32(Size), Op, Data/binary>>]).
xf_send_name(XF, ReqId, Name, Attr) ->
xf_send_names(XF, ReqId, [{Name, Attr}]).
diff --git a/lib/ssh/src/sshc_sup.erl b/lib/ssh/src/sshc_sup.erl
index 1d2779de23..e6b4b681a4 100644
--- a/lib/ssh/src/sshc_sup.erl
+++ b/lib/ssh/src/sshc_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2008-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
@@ -61,9 +61,9 @@ init(Args) ->
%%%=========================================================================
child_spec(_) ->
Name = undefined, % As simple_one_for_one is used.
- StartFunc = {ssh_connection_sup, start_link, []},
+ StartFunc = {ssh_connection_handler, start_link, []},
Restart = temporary,
Shutdown = infinity,
- Modules = [ssh_connection_sup],
+ Modules = [ssh_connection_handler],
Type = supervisor,
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
diff --git a/lib/ssh/test/Makefile b/lib/ssh/test/Makefile
index f5db31baee..740dbd0235 100644
--- a/lib/ssh/test/Makefile
+++ b/lib/ssh/test/Makefile
@@ -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
@@ -38,7 +38,9 @@ MODULES= \
ssh_sftpd_SUITE \
ssh_sftpd_erlclient_SUITE \
ssh_connection_SUITE \
- ssh_echo_server
+ ssh_echo_server \
+ ssh_peername_sockname_server \
+ ssh_test_cli
HRL_FILES_NEEDED_IN_TEST= \
$(ERL_TOP)/lib/ssh/src/ssh.hrl \
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 0aa60624bf..b3281e433e 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -22,6 +22,7 @@
-module(ssh_basic_SUITE).
-include_lib("common_test/include/ct.hrl").
+-include_lib("kernel/include/inet.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -48,12 +49,18 @@ all() ->
close].
groups() ->
- [{dsa_key, [], [send, exec, exec_compressed, shell, known_hosts, idle_time, rekey, openssh_zlib_basic_test]},
- {rsa_key, [], [send, exec, exec_compressed, shell, known_hosts, idle_time, rekey, openssh_zlib_basic_test]},
+ [{dsa_key, [], basic_tests()},
+ {rsa_key, [], basic_tests()},
{dsa_pass_key, [], [pass_phrase]},
{rsa_pass_key, [], [pass_phrase]},
{internal_error, [], [internal_error]}
].
+
+basic_tests() ->
+ [send, peername_sockname,
+ exec, exec_compressed, shell, cli, known_hosts,
+ idle_time, rekey, openssh_zlib_basic_test].
+
%%--------------------------------------------------------------------
init_per_suite(Config) ->
case catch crypto:start() of
@@ -252,7 +259,7 @@ idle_time(Config) ->
ssh_connection:close(ConnectionRef, Id),
receive
after 10000 ->
- {error,channel_closed} = ssh_connection:session_channel(ConnectionRef, 1000)
+ {error, closed} = ssh_connection:session_channel(ConnectionRef, 1000)
end,
ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
@@ -300,6 +307,41 @@ shell(Config) when is_list(Config) ->
end.
%%--------------------------------------------------------------------
+cli() ->
+ [{doc, ""}].
+cli(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+
+ {_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},{user_dir, UserDir},
+ {password, "morot"},
+ {ssh_cli, {ssh_test_cli, [cli]}},
+ {subsystems, []},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ ct:sleep(500),
+
+ ConnectionRef = ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user, "foo"},
+ {password, "morot"},
+ {user_interaction, false},
+ {user_dir, UserDir}]),
+
+ {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
+ ssh_connection:shell(ConnectionRef, ChannelId),
+ ok = ssh_connection:send(ConnectionRef, ChannelId, <<"q">>),
+ receive
+ {ssh_cm, ConnectionRef,
+ {data,0,0, <<"\r\nYou are accessing a dummy, type \"q\" to exit\r\n\n">>}} ->
+ ok = ssh_connection:send(ConnectionRef, ChannelId, <<"q">>)
+ end,
+
+ receive
+ {ssh_cm, ConnectionRef,{closed, ChannelId}} ->
+ ok
+ end.
+
+%%--------------------------------------------------------------------
daemon_already_started() ->
[{doc, "Test that get correct error message if you try to start a daemon",
"on an adress that already runs a daemon see also seq10667"}].
@@ -445,10 +487,11 @@ internal_error(Config) when is_list(Config) ->
{Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
{user_dir, UserDir},
{failfun, fun ssh_test_lib:failfun/2}]),
- {error,"Internal error"} =
+ {error,Error} =
ssh:connect(Host, Port, [{silently_accept_hosts, true},
{user_dir, UserDir},
{user_interaction, false}]),
+ check_error(Error),
ssh:stop_daemon(Pid).
%%--------------------------------------------------------------------
@@ -473,6 +516,56 @@ send(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
+peername_sockname() ->
+ [{doc, "Test ssh:connection_info([peername, sockname])"}].
+peername_sockname(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ SystemDir = filename:join(?config(priv_dir, Config), system),
+ UserDir = ?config(priv_dir, Config),
+
+ {_Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {subsystems, [{"peername_sockname",
+ {ssh_peername_sockname_server, []}}
+ ]}
+ ]),
+ ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user_interaction, false}]),
+ {ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
+ success = ssh_connection:subsystem(ConnectionRef, ChannelId, "peername_sockname", infinity),
+ [{peer, {_Name, {HostPeerClient,PortPeerClient} = ClientPeer}}] =
+ ssh:connection_info(ConnectionRef, [peer]),
+ [{sockname, {HostSockClient,PortSockClient} = ClientSock}] =
+ ssh:connection_info(ConnectionRef, [sockname]),
+ ct:pal("Client: ~p ~p", [ClientPeer, ClientSock]),
+ receive
+ {ssh_cm, ConnectionRef, {data, ChannelId, _, Response}} ->
+ {PeerNameSrv,SockNameSrv} = binary_to_term(Response),
+ {HostPeerSrv,PortPeerSrv} = PeerNameSrv,
+ {HostSockSrv,PortSockSrv} = SockNameSrv,
+ ct:pal("Server: ~p ~p", [PeerNameSrv, SockNameSrv]),
+ host_equal(HostPeerSrv, HostSockClient),
+ PortPeerSrv = PortSockClient,
+ host_equal(HostSockSrv, HostPeerClient),
+ PortSockSrv = PortPeerClient,
+ host_equal(HostSockSrv, Host),
+ PortSockSrv = Port
+ after 10000 ->
+ throw(timeout)
+ end.
+
+host_equal(H1, H2) ->
+ not ordsets:is_disjoint(ips(H1), ips(H2)).
+
+ips(IP) when is_tuple(IP) -> ordsets:from_list([IP]);
+ips(Name) when is_list(Name) ->
+ {ok,#hostent{h_addr_list=IPs4}} = inet:gethostbyname(Name,inet),
+ {ok,#hostent{h_addr_list=IPs6}} = inet:gethostbyname(Name,inet6),
+ ordsets:from_list(IPs4++IPs6).
+
+%%--------------------------------------------------------------------
close() ->
[{doc, "Simulate that we try to close an already closed connection"}].
close(Config) when is_list(Config) ->
@@ -515,6 +608,15 @@ openssh_zlib_basic_test(Config) ->
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
+%% Due to timing the error message may or may not be delivered to
+%% the "tcp-application" before the socket closed message is recived
+check_error("Internal error") ->
+ ok;
+check_error("Connection Lost") ->
+ ok;
+check_error(Error) ->
+ ct:fail(Error).
+
basic_test(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index 6c781e0e91..f4f0682b40 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -73,6 +73,9 @@ end_per_group(_, Config) ->
%%--------------------------------------------------------------------
init_per_testcase(_TestCase, Config) ->
+ %% To make sure we start clean as it is not certain that
+ %% end_per_testcase will be run!
+ ssh:stop(),
ssh:start(),
Config.
@@ -91,7 +94,6 @@ simple_exec(Config) when is_list(Config) ->
{ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
success = ssh_connection:exec(ConnectionRef, ChannelId0,
"echo testing", infinity),
-
%% receive response to input
receive
{ssh_cm, ConnectionRef, {data, ChannelId0, 0, <<"testing\n">>}} ->
@@ -146,7 +148,6 @@ small_cat(Config) when is_list(Config) ->
{ssh_cm, ConnectionRef,{closed, ChannelId0}} ->
ok
end.
-
%%--------------------------------------------------------------------
big_cat() ->
[{doc,"Use 'cat' to echo large data block back to us."}].
@@ -204,37 +205,33 @@ send_after_exit(Config) when is_list(Config) ->
ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
{user_interaction, false}]),
{ok, ChannelId0} = ssh_connection:session_channel(ConnectionRef, infinity),
+ Data = <<"I like spaghetti squash">>,
%% Shell command "false" will exit immediately
success = ssh_connection:exec(ConnectionRef, ChannelId0,
"false", infinity),
-
- timer:sleep(2000), %% Allow incoming eof/close/exit_status ssh messages to be processed
-
- Data = <<"I like spaghetti squash">>,
- case ssh_connection:send(ConnectionRef, ChannelId0, Data, 2000) of
- {error, closed} -> ok;
- ok ->
- ct:fail({expected,{error,closed}});
- {error, timeout} ->
- ct:fail({expected,{error,closed}});
- Else ->
- ct:fail(Else)
- end,
-
- %% receive close messages
receive
{ssh_cm, ConnectionRef, {eof, ChannelId0}} ->
ok
end,
receive
- {ssh_cm, ConnectionRef, {exit_status, ChannelId0, _}} ->
+ {ssh_cm, ConnectionRef, {exit_status, ChannelId0, _ExitStatus}} ->
ok
end,
receive
{ssh_cm, ConnectionRef,{closed, ChannelId0}} ->
ok
+ end,
+ case ssh_connection:send(ConnectionRef, ChannelId0, Data, 2000) of
+ {error, closed} -> ok;
+ ok ->
+ ct:fail({expected,{error,closed}, {got, ok}});
+ {error, timeout} ->
+ ct:fail({expected,{error,closed}, {got, {error, timeout}}});
+ Else ->
+ ct:fail(Else)
end.
+
%%--------------------------------------------------------------------
interrupted_send() ->
[{doc, "Use a subsystem that echos n char and then sends eof to cause a channel exit partway through a large send."}].
diff --git a/lib/ssh/test/ssh_peername_sockname_server.erl b/lib/ssh/test/ssh_peername_sockname_server.erl
new file mode 100644
index 0000000000..bc505695d3
--- /dev/null
+++ b/lib/ssh/test/ssh_peername_sockname_server.erl
@@ -0,0 +1,54 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-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(ssh_peername_sockname_server).
+
+%% The purpose of this module is to perform tests on the server side of an
+%% ssh connection.
+
+
+-behaviour(ssh_daemon_channel).
+-record(state, {}).
+
+-export([init/1, handle_msg/2, handle_ssh_msg/2, terminate/2]).
+
+init([]) ->
+ {ok, #state{}}.
+
+handle_msg({ssh_channel_up, ChannelId, ConnectionManager}, State) ->
+ [{peer, {_Name, Peer}}] = ssh:connection_info(ConnectionManager, [peer]),
+ [{sockname, Sock}] = ssh:connection_info(ConnectionManager, [sockname]),
+ ssh_connection:send(ConnectionManager, ChannelId,
+ term_to_binary({Peer, Sock})),
+ {ok, State}.
+
+handle_ssh_msg({ssh_cm, _, {exit_signal, ChannelId, _, _Error, _}},
+ State) ->
+ {stop, ChannelId, State};
+
+handle_ssh_msg({ssh_cm, _, {exit_status, ChannelId, _Status}}, State) ->
+ {stop, ChannelId, State};
+
+handle_ssh_msg({ssh_cm, _CM, _}, State) ->
+ {ok, State}.
+
+terminate(_Reason, _State) ->
+ ok.
diff --git a/lib/ssh/test/ssh_test_cli.erl b/lib/ssh/test/ssh_test_cli.erl
new file mode 100644
index 0000000000..cd9ad5f2ff
--- /dev/null
+++ b/lib/ssh/test/ssh_test_cli.erl
@@ -0,0 +1,81 @@
+-module(ssh_test_cli).
+
+-export([init/1, terminate/2, handle_ssh_msg/2, handle_msg/2]).
+
+-record(state, {
+ type,
+ id,
+ ref,
+ port
+ }).
+
+init([Type]) ->
+ {ok, #state{type = Type}}.
+
+handle_msg({ssh_channel_up, Id, Ref}, S) ->
+ User = get_ssh_user(Ref),
+ ok = ssh_connection:send(Ref,
+ Id,
+ << "\r\nYou are accessing a dummy, type \"q\" to exit\r\n\n" >>),
+ Port = run_portprog(User, S#state.type),
+ {ok, S#state{port = Port, id = Id, ref = Ref}};
+
+handle_msg({Port, {data, Data}}, S = #state{port = Port}) ->
+ ok = ssh_connection:send(S#state.ref, S#state.id, Data),
+ {ok, S};
+handle_msg({Port, {exit_status, Exit}}, S = #state{port = Port}) ->
+ if
+ S#state.type =:= cli ->
+ ok = ssh_connection:send(S#state.ref, S#state.id, << "\r\n" >>);
+ true ->
+ ok
+ end,
+ ok = ssh_connection:exit_status(S#state.ref, S#state.id, Exit),
+ {stop, S#state.id, S#state{port = undefined}};
+handle_msg({'EXIT', Port, _}, S = #state{port = Port}) ->
+ ok = ssh_connection:exit_status(S#state.ref, S#state.id, 0),
+ {stop, S#state.id, S#state{port = undefined}};
+handle_msg(_Msg, S) ->
+ {ok, S}.
+
+handle_ssh_msg({ssh_cm, Ref, {data, Id, _Type, <<"q">>}}, S) ->
+ ssh_connection:send_eof(Ref, Id),
+ {stop, Id, S};
+handle_ssh_msg({ssh_cm, _Ref, {data, _Id, _Type, Data}}, S) ->
+ true = port_command(S#state.port, Data),
+ {ok, S};
+handle_ssh_msg({ssh_cm, _, {eof, _}}, S) ->
+ {ok, S};
+handle_ssh_msg({ssh_cm, Ref, {env, Id, WantReply, _Var, _Value}}, S) ->
+ ok = ssh_connection:reply_request(Ref, WantReply, success, Id),
+ {ok, S};
+handle_ssh_msg({ssh_cm, Ref, {pty, Id, WantReply, _Terminal_jox}}, S) ->
+ ok = ssh_connection:reply_request(Ref, WantReply, success, Id),
+ {ok, S};
+handle_ssh_msg({ssh_cm, Ref, {shell, Id, WantReply}}, S) ->
+ ok = ssh_connection:reply_request(Ref, WantReply, success, Id),
+ {ok, S};
+handle_ssh_msg({ssh_cm, _, {signal, _, _}}, S) ->
+ %% Ignore signals according to RFC 4254 section 6.9.
+ {ok, S};
+handle_ssh_msg({ssh_cm, _,
+ {window_change, _Id, _Width, _Height, _Pixw, _PixH}}, S) ->
+ {ok, S};
+handle_ssh_msg({ssh_cm, _, {exit_signal, Id, _, _, _}},
+ S) ->
+ {stop, Id, S}.
+
+terminate(_Why, _S) ->
+ nop.
+
+run_portprog(User, cli) ->
+ Pty_bin = os:find_executable("cat"),
+ open_port({spawn_executable, Pty_bin},
+ [stream, {cd, "/tmp"}, {env, [{"USER", User}]},
+ {args, []}, binary,
+ exit_status, use_stdio, stderr_to_stdout]).
+
+get_ssh_user(Ref) ->
+ [{user, User}] = ssh:connection_info(Ref, [user]),
+ User.
+
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 6029a09730..19c0c8c9ee 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -52,6 +52,8 @@
<item>CRL and policy certificate extensions are not supported
yet. However CRL verification is supported by public_key, only not integrated
in ssl yet. </item>
+ <item>Support for 'Server Name Indication' extension client side
+ (RFC 6066 section 3).</item>
</list>
</section>
@@ -86,8 +88,8 @@
{user_lookup_fun, {fun(), term()}}, {psk_identity, string()}, {srp_identity, {string(), string()}} |
{ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()}
{next_protocols_advertised, [binary()]} |
- {client_preferred_next_protocols, client | server, [binary()]} |
- {log_alert, boolean()}
+ {client_preferred_next_protocols, {client | server, [binary()]} | {client | server, [binary()], binary()}} |
+ {log_alert, boolean()} | {server_name_indication, hostname() | disable}
</c></p>
<p><c>transportoption() = {cb_info, {CallbackModule::atom(), DataTag::atom(), ClosedTag::atom(), ErrTag:atom()}}
@@ -353,8 +355,8 @@ fun(srp, Username :: string(), UserState :: term()) ->
when possible.
</item>
- <tag>{client_preferred_next_protocols, Precedence :: server | client, ClientPrefs :: [binary()]}</tag>
- <tag>{client_preferred_next_protocols, Precedence :: server | client, ClientPrefs :: [binary()], Default :: binary()}</tag>
+ <tag>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()]}}</tag>
+ <tag>{client_preferred_next_protocols, {Precedence :: server | client, ClientPrefs :: [binary()], Default :: binary()}}</tag>
<item>
<p>Indicates the client will try to perform Next Protocol
Negotiation.</p>
@@ -382,6 +384,15 @@ fun(srp, Username :: string(), UserState :: term()) ->
<tag>{srp_identity, {Username :: string(), Password :: string()}</tag>
<item>Specifies the Username and Password to use to authenticate to the server.
</item>
+ <tag>{server_name_indication, hostname()}</tag>
+ <tag>{server_name_indication, disable}</tag>
+ <item>
+ <p>This option can be specified when upgrading a TCP socket to a TLS
+ socket to use the TLS Server Name Indication extension.</p>
+ <p>When starting a TLS connection without upgrade the Server Name
+ Indication extension will be sent if possible, this option may also be
+ used to disable that behavior.</p>
+ </item>
</taglist>
</section>
diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl
index 26e8ce7503..d0f9649f9f 100644
--- a/lib/ssl/src/dtls_handshake.erl
+++ b/lib/ssl/src/dtls_handshake.erl
@@ -46,7 +46,7 @@ client_hello(Host, Port, Cookie, ConnectionStates,
SecParams = Pending#connection_state.security_parameters,
CipherSuites = ssl_handshake:available_suites(UserSuites, Version),
- Extensions = ssl_handshake:client_hello_extensions(Version, CipherSuites,
+ Extensions = ssl_handshake:client_hello_extensions(Host, Version, CipherSuites,
SslOpts, ConnectionStates, Renegotiation),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl
index 57c859bf24..7367b5c224 100644
--- a/lib/ssl/src/inet_tls_dist.erl
+++ b/lib/ssl/src/inet_tls_dist.erl
@@ -95,11 +95,6 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
end.
close(Socket) ->
- try
- erlang:error(foo)
- catch _:_ ->
- io:format("close called ~p ~p~n",[Socket, erlang:get_stacktrace()])
- end,
gen_tcp:close(Socket),
ok.
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 6513042e98..e6ed0d8626 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -34,7 +34,7 @@
-export([security_parameters/2, security_parameters/3, suite_definition/1,
decipher/5, cipher/5,
- suite/1, suites/1, anonymous_suites/0, psk_suites/1, srp_suites/0,
+ suite/1, suites/1, ec_keyed_suites/0, anonymous_suites/0, psk_suites/1, srp_suites/0,
openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2]).
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 29a8996bd6..9142a260b1 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -49,13 +49,13 @@
]).
%% Cipher suites handling
--export([available_suites/2, available_suites/3, cipher_suites/2,
- select_session/10]).
+-export([available_suites/2, cipher_suites/2,
+ select_session/10, supported_ecc/1]).
%% Extensions handling
--export([client_hello_extensions/5,
+-export([client_hello_extensions/6,
handle_client_hello_extensions/8, %% Returns server hello extensions
- handle_server_hello_extensions/9
+ handle_server_hello_extensions/9, select_curve/2
]).
%% MISC
@@ -85,11 +85,11 @@ hello_request() ->
server_hello_done() ->
#server_hello_done{}.
-client_hello_extensions(Version, CipherSuites, SslOpts, ConnectionStates, Renegotiation) ->
+client_hello_extensions(Host, Version, CipherSuites, SslOpts, ConnectionStates, Renegotiation) ->
{EcPointFormats, EllipticCurves} =
case advertises_ec_ciphers(lists:map(fun ssl_cipher:suite_definition/1, CipherSuites)) of
true ->
- ecc_extensions(tls_v1, Version);
+ client_ecc_extensions(tls_v1, Version);
false ->
{undefined, undefined}
end,
@@ -104,7 +104,8 @@ client_hello_extensions(Version, CipherSuites, SslOpts, ConnectionStates, Renego
elliptic_curves = EllipticCurves,
next_protocol_negotiation =
encode_client_protocol_negotiation(SslOpts#ssl_options.next_protocol_selector,
- Renegotiation)}.
+ Renegotiation),
+ sni = sni(Host, SslOpts#ssl_options.server_name_indication)}.
%%--------------------------------------------------------------------
-spec certificate(der_cert(), db_handle(), certdb_ref(), client | server) -> #certificate{} | #alert{}.
@@ -641,7 +642,19 @@ encode_hello_extensions([#hash_sign_algos{hash_sign_algos = HashSignAlgos} | Res
ListLen = byte_size(SignAlgoList),
Len = ListLen + 2,
encode_hello_extensions(Rest, <<?UINT16(?SIGNATURE_ALGORITHMS_EXT),
- ?UINT16(Len), ?UINT16(ListLen), SignAlgoList/binary, Acc/binary>>).
+ ?UINT16(Len), ?UINT16(ListLen), SignAlgoList/binary, Acc/binary>>);
+encode_hello_extensions([#sni{hostname = Hostname} | Rest], Acc) ->
+ HostLen = length(Hostname),
+ HostnameBin = list_to_binary(Hostname),
+ % Hostname type (1 byte) + Hostname length (2 bytes) + Hostname (HostLen bytes)
+ ServerNameLength = 1 + 2 + HostLen,
+ % ServerNameListSize (2 bytes) + ServerNameLength
+ ExtLength = 2 + ServerNameLength,
+ encode_hello_extensions(Rest, <<?UINT16(?SNI_EXT), ?UINT16(ExtLength),
+ ?UINT16(ServerNameLength),
+ ?BYTE(?SNI_NAMETYPE_HOST_NAME),
+ ?UINT16(HostLen), HostnameBin/binary,
+ Acc/binary>>).
enc_server_key_exchange(Version, Params, {HashAlgo, SignAlgo},
ClientRandom, ServerRandom, PrivateKey) ->
@@ -861,22 +874,29 @@ available_suites(UserSuites, Version) ->
UserSuites
end.
-available_suites(ServerCert, UserSuites, Version) ->
- ssl_cipher:filter(ServerCert, available_suites(UserSuites, Version)).
+available_suites(ServerCert, UserSuites, Version, Curve) ->
+ ssl_cipher:filter(ServerCert, available_suites(UserSuites, Version))
+ -- unavailable_ecc_suites(Curve).
+
+unavailable_ecc_suites(no_curve) ->
+ ssl_cipher:ec_keyed_suites();
+unavailable_ecc_suites(_) ->
+ [].
cipher_suites(Suites, false) ->
[?TLS_EMPTY_RENEGOTIATION_INFO_SCSV | Suites];
cipher_suites(Suites, true) ->
Suites.
-select_session(SuggestedSessionId, CipherSuites, Compressions, Port, Session, Version,
+select_session(SuggestedSessionId, CipherSuites, Compressions, Port, #session{ecc = ECCCurve} =
+ Session, Version,
#ssl_options{ciphers = UserSuites} = SslOpts, Cache, CacheCb, Cert) ->
{SessionId, Resumed} = ssl_session:server_id(Port, SuggestedSessionId,
SslOpts, Cert,
Cache, CacheCb),
- Suites = ssl_handshake:available_suites(Cert, UserSuites, Version),
case Resumed of
undefined ->
+ Suites = available_suites(Cert, UserSuites, Version, ECCCurve),
CipherSuite = select_cipher_suite(CipherSuites, Suites),
Compression = select_compression(Compressions),
{new, Session#session{session_id = SessionId,
@@ -886,6 +906,13 @@ select_session(SuggestedSessionId, CipherSuites, Compressions, Port, Session, Ve
{resumed, Resumed}
end.
+supported_ecc(Version) ->
+ case tls_v1:ecc_curves(Version) of
+ [] ->
+ undefined;
+ Curves ->
+ #elliptic_curves{elliptic_curve_list = Curves}
+ end.
%%-------------certificate handling --------------------------------
certificate_types({KeyExchange, _, _, _})
@@ -926,9 +953,8 @@ certificate_authorities_from_db(CertDbHandle, CertDbRef) ->
handle_client_hello_extensions(RecordCB, Random,
#hello_extensions{renegotiation_info = Info,
srp = SRP,
- next_protocol_negotiation = NextProtocolNegotiation,
- ec_point_formats = EcPointFormats0,
- elliptic_curves = EllipticCurves0}, Version,
+ ec_point_formats = ECCFormat,
+ next_protocol_negotiation = NextProtocolNegotiation}, Version,
#ssl_options{secure_renegotiate = SecureRenegotation} = Opts,
#session{cipher_suite = CipherSuite, compression_method = Compression} = Session0,
ConnectionStates0, Renegotiation) ->
@@ -937,12 +963,11 @@ handle_client_hello_extensions(RecordCB, Random,
Random, CipherSuite, Compression,
ConnectionStates0, Renegotiation, SecureRenegotation),
ProtocolsToAdvertise = handle_next_protocol_extension(NextProtocolNegotiation, Renegotiation, Opts),
- {EcPointFormats, EllipticCurves} = handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0),
+
ServerHelloExtensions = #hello_extensions{
renegotiation_info = renegotiation_info(RecordCB, server,
ConnectionStates, Renegotiation),
- ec_point_formats = EcPointFormats,
- elliptic_curves = EllipticCurves,
+ ec_point_formats = server_ecc_extension(Version, ECCFormat),
next_protocol_negotiation =
encode_protocols_advertised_on_server(ProtocolsToAdvertise)
},
@@ -1069,16 +1094,17 @@ hello_extensions_list(#hello_extensions{renegotiation_info = RenegotiationInfo,
hash_signs = HashSigns,
ec_point_formats = EcPointFormats,
elliptic_curves = EllipticCurves,
- next_protocol_negotiation = NextProtocolNegotiation}) ->
+ next_protocol_negotiation = NextProtocolNegotiation,
+ sni = Sni}) ->
[Ext || Ext <- [RenegotiationInfo, SRP, HashSigns,
- EcPointFormats,EllipticCurves, NextProtocolNegotiation], Ext =/= undefined].
+ EcPointFormats, EllipticCurves, NextProtocolNegotiation, Sni], Ext =/= undefined].
srp_user(#ssl_options{srp_identity = {UserName, _}}) ->
#srp{username = UserName};
srp_user(_) ->
undefined.
-ecc_extensions(Module, Version) ->
+client_ecc_extensions(Module, Version) ->
CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
case proplists:get_bool(ecdh, CryptoSupport) of
true ->
@@ -1089,15 +1115,13 @@ ecc_extensions(Module, Version) ->
{undefined, undefined}
end.
-handle_ecc_extensions(Version, EcPointFormats0, EllipticCurves0) ->
+server_ecc_extension(_Version, EcPointFormats) ->
CryptoSupport = proplists:get_value(public_keys, crypto:supports()),
case proplists:get_bool(ecdh, CryptoSupport) of
true ->
- EcPointFormats1 = handle_ecc_point_fmt_extension(EcPointFormats0),
- EllipticCurves1 = handle_ecc_curves_extension(Version, EllipticCurves0),
- {EcPointFormats1, EllipticCurves1};
- _ ->
- {undefined, undefined}
+ handle_ecc_point_fmt_extension(EcPointFormats);
+ false ->
+ undefined
end.
handle_ecc_point_fmt_extension(undefined) ->
@@ -1105,11 +1129,6 @@ 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) ->
- undefined;
-handle_ecc_curves_extension(Version, _) ->
- #elliptic_curves{elliptic_curve_list = tls_v1:ecc_curves(Version)}.
-
advertises_ec_ciphers([]) ->
false;
advertises_ec_ciphers([{ecdh_ecdsa, _,_,_} | _]) ->
@@ -1124,7 +1143,36 @@ advertises_ec_ciphers([{ecdh_anon, _,_,_} | _]) ->
true;
advertises_ec_ciphers([_| Rest]) ->
advertises_ec_ciphers(Rest).
-
+select_curve(#elliptic_curves{elliptic_curve_list = ClientCurves},
+ #elliptic_curves{elliptic_curve_list = ServerCurves}) ->
+ select_curve(ClientCurves, ServerCurves);
+select_curve(undefined, _) ->
+ %% Client did not send ECC extension use default curve if
+ %% ECC cipher is negotiated
+ {namedCurve, ?secp256k1};
+select_curve(_, []) ->
+ no_curve;
+select_curve(Curves, [Curve| Rest]) ->
+ case lists:member(Curve, Curves) of
+ true ->
+ {namedCurve, Curve};
+ false ->
+ select_curve(Curves, Rest)
+ end.
+%% RFC 6066, Section 3: Currently, the only server names supported are
+%% DNS hostnames
+sni(_, disable) ->
+ undefined;
+sni(Host, undefined) ->
+ sni1(Host);
+sni(_Host, SNIOption) ->
+ sni1(SNIOption).
+
+sni1(Hostname) ->
+ case inet_parse:domain(Hostname) of
+ false -> undefined;
+ true -> #sni{hostname = Hostname}
+ end.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -1648,3 +1696,4 @@ advertised_hash_signs({Major, Minor}) when Major >= 3 andalso Minor >= 3 ->
({Hash, _}) -> proplists:get_bool(Hash, Hashs) end, HashSigns)};
advertised_hash_signs(_) ->
undefined.
+
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 3a3ad8cf35..75160526b9 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -45,7 +45,8 @@
master_secret,
srp_username,
is_resumable,
- time_stamp
+ time_stamp,
+ ecc
}).
-define(NUM_OF_SESSION_ID_BYTES, 32). % TSL 1.1 & SSL 3
@@ -97,7 +98,8 @@
next_protocol_negotiation = undefined, % [binary()]
srp,
ec_point_formats,
- elliptic_curves
+ elliptic_curves,
+ sni
}).
-record(server_hello, {
@@ -338,6 +340,19 @@
-define(NAMED_CURVE, 3).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Server name indication RFC 6066 section 3
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+-define(SNI_EXT, 16#0000).
+
+%% enum { host_name(0), (255) } NameType;
+-define(SNI_NAMETYPE_HOST_NAME, 0).
+
+-record(sni, {
+ hostname = undefined
+ }).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Dialyzer types
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -352,6 +367,3 @@
-endif. % -ifdef(ssl_handshake).
-
-
-
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 96e3280fb5..a582b8c290 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -115,7 +115,8 @@
erl_dist = false,
next_protocols_advertised = undefined, %% [binary()],
next_protocol_selector = undefined, %% fun([binary()]) -> binary())
- log_alert
+ log_alert,
+ server_name_indication = undefined
}).
-record(socket_options,
diff --git a/lib/ssl/src/tls.erl b/lib/ssl/src/tls.erl
index b220a48f73..f1747dc69e 100644
--- a/lib/ssl/src/tls.erl
+++ b/lib/ssl/src/tls.erl
@@ -664,7 +664,8 @@ handle_options(Opts0, _Role) ->
next_protocol_selector =
make_next_protocol_selector(
handle_option(client_preferred_next_protocols, Opts, undefined)),
- log_alert = handle_option(log_alert, Opts, true)
+ log_alert = handle_option(log_alert, Opts, true),
+ server_name_indication = handle_option(server_name_indication, Opts, undefined)
},
CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}),
@@ -855,6 +856,12 @@ validate_option(next_protocols_advertised = Opt, Value) when is_list(Value) ->
validate_option(next_protocols_advertised, undefined) ->
undefined;
+validate_option(server_name_indication, Value) when is_list(Value) ->
+ Value;
+validate_option(server_name_indication, disable) ->
+ disable;
+validate_option(server_name_indication, undefined) ->
+ undefined;
validate_option(Opt, Value) ->
throw({error, {options, {Opt, Value}}}).
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index 5618837506..39595b4f95 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -97,8 +97,7 @@
terminated = false, %
allow_renegotiate = true,
expecting_next_protocol_negotiation = false :: boolean(),
- next_protocol = undefined :: undefined | binary(),
- client_ecc % {Curves, PointFmt}
+ next_protocol = undefined :: undefined | binary()
}).
-define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
@@ -405,26 +404,24 @@ hello(#server_hello{cipher_suite = CipherSuite,
hello(Hello = #client_hello{client_version = ClientVersion,
extensions = #hello_extensions{hash_signs = HashSigns}},
State = #state{connection_states = ConnectionStates0,
- port = Port, session = #session{own_certificate = Cert} = Session0,
+ port = Port,
+ session = #session{own_certificate = Cert} = Session0,
renegotiation = {Renegotiation, _},
session_cache = Cache,
session_cache_cb = CacheCb,
ssl_options = SslOpts}) ->
HashSign = ssl_handshake:select_hashsign(HashSigns, Cert),
case tls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
- ConnectionStates0, Cert}, Renegotiation) of
+ ConnectionStates0, Cert}, Renegotiation) of
{Version, {Type, #session{cipher_suite = CipherSuite} = Session},
- ConnectionStates,
- #hello_extensions{ec_point_formats = EcPointFormats,
- elliptic_curves = EllipticCurves} = ServerHelloExt} ->
+ ConnectionStates, ServerHelloExt} ->
{KeyAlg, _, _, _} = ssl_cipher:suite_definition(CipherSuite),
- NegotiatedHashSign = negotiated_hashsign(HashSign, KeyAlg, Version),
- do_server_hello(Type, ServerHelloExt,
+ NegotiatedHashSign = negotiated_hashsign(HashSign, KeyAlg, Version),
+ do_server_hello(Type, ServerHelloExt,
State#state{connection_states = ConnectionStates,
negotiated_version = Version,
session = Session,
- hashsign_algorithm = NegotiatedHashSign,
- client_ecc = {EllipticCurves, EcPointFormats}});
+ hashsign_algorithm = NegotiatedHashSign});
#alert{} = Alert ->
handle_own_alert(Alert, ClientVersion, hello, State)
end;
@@ -1647,12 +1644,13 @@ key_exchange(#state{role = server, key_algorithm = Algo,
negotiated_version = Version,
tls_handshake_history = Handshake0,
socket = Socket,
- transport_cb = Transport
+ transport_cb = Transport,
+ session = #session{ecc = Curve}
} = State)
when Algo == ecdhe_ecdsa; Algo == ecdhe_rsa;
Algo == ecdh_anon ->
- ECDHKeys = public_key:generate_key(select_curve(State)),
+ ECDHKeys = public_key:generate_key(Curve),
ConnectionState =
ssl_record:pending_connection_state(ConnectionStates0, read),
SecParams = ConnectionState#connection_state.security_parameters,
@@ -3086,12 +3084,7 @@ default_hashsign(_Version, KeyExchange)
KeyExchange == rsa_psk;
KeyExchange == srp_anon ->
{null, anon}.
-
-select_curve(#state{client_ecc = {[Curve|_], _}}) ->
- {namedCurve, Curve};
-select_curve(_) ->
- {namedCurve, ?secp256k1}.
-
+
is_anonymous(Algo) when Algo == dh_anon;
Algo == ecdh_anon;
Algo == psk;
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 02bfa69fc5..262f2d929f 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -56,7 +56,7 @@ client_hello(Host, Port, ConnectionStates,
SecParams = Pending#connection_state.security_parameters,
CipherSuites = ssl_handshake:available_suites(UserSuites, Version),
- Extensions = ssl_handshake:client_hello_extensions(Version, CipherSuites,
+ Extensions = ssl_handshake:client_hello_extensions(Host, Version, CipherSuites,
SslOpts, ConnectionStates, Renegotiation),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -70,7 +70,7 @@ client_hello(Host, Port, ConnectionStates,
}.
%%--------------------------------------------------------------------
--spec server_hello(#session{}, tls_version(), #connection_states{},
+-spec server_hello(binary(), tls_version(), #connection_states{},
#hello_extensions{}) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
@@ -120,17 +120,16 @@ hello(#client_hello{client_version = ClientVersion,
cipher_suites = CipherSuites,
compression_methods = Compressions,
random = Random,
- extensions = HelloExt},
+ extensions = #hello_extensions{elliptic_curves = Curves} = HelloExt},
#ssl_options{versions = Versions} = SslOpts,
{Port, Session0, Cache, CacheCb, ConnectionStates0, Cert}, Renegotiation) ->
Version = ssl_handshake:select_version(tls_record, ClientVersion, Versions),
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
+ ECCCurve = ssl_handshake:select_curve(Curves, ssl_handshake:supported_ecc(Version)),
{Type, #session{cipher_suite = CipherSuite} = Session1}
= ssl_handshake:select_session(SugesstedId, CipherSuites, Compressions,
- Port, Session0, Version,
+ Port, Session0#session{ecc = ECCCurve}, Version,
SslOpts, Cache, CacheCb, Cert),
case CipherSuite of
no_suite ->
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index 9695710230..7e8e8d2611 100644
--- a/lib/ssl/test/ssl_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_handshake_SUITE.erl
@@ -34,7 +34,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() -> [decode_hello_handshake,
decode_single_hello_extension_correctly,
- decode_unknown_hello_extension_correctly].
+ decode_unknown_hello_extension_correctly,
+ encode_single_hello_sni_extension_correctly].
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
@@ -73,3 +74,12 @@ decode_unknown_hello_extension_correctly(_Config) ->
Extensions = ssl_handshake:decode_hello_extensions(<<FourByteUnknown/binary, Renegotiation/binary>>),
#renegotiation_info{renegotiated_connection = <<0>>}
= Extensions#hello_extensions.renegotiation_info.
+
+encode_single_hello_sni_extension_correctly(_Config) ->
+ Exts = #hello_extensions{sni = #sni{hostname = "test.com"}},
+ SNI = <<16#00, 16#00, 16#00, 16#0d, 16#00, 16#0b, 16#00, 16#00, 16#08,
+ $t, $e, $s, $t, $., $c, $o, $m>>,
+ ExtSize = byte_size(SNI),
+ HelloExt = <<ExtSize:16/unsigned-big-integer, SNI/binary>>,
+ Encoded = ssl_handshake:encode_hello_extensions(Exts),
+ HelloExt = Encoded.
diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml
index 71a6e34513..7a9f37ca90 100644
--- a/lib/stdlib/doc/src/re.xml
+++ b/lib/stdlib/doc/src/re.xml
@@ -40,8 +40,8 @@
<p>This module contains regular expression matching functions for
strings and binaries.</p>
- <p>The regular expression syntax and semantics resemble that of
- Perl.</p>
+ <p>The <seealso marker="#regexp_syntax">regular expression</seealso>
+ syntax and semantics resemble that of Perl.</p>
<p>The library's matching algorithms are currently based on the
PCRE library, but not all of the PCRE library is interfaced and
@@ -702,7 +702,7 @@ This option makes it possible to include comments inside complicated patterns. N
</func>
</funcs>
-
+ <marker id="regexp_syntax"></marker>
<section>
<title>PERL LIKE REGULAR EXPRESSIONS SYNTAX</title>
<p>The following sections contain reference material for the
diff --git a/lib/stdlib/src/dict.erl b/lib/stdlib/src/dict.erl
index 4f8d45dc8d..4b42f64609 100644
--- a/lib/stdlib/src/dict.erl
+++ b/lib/stdlib/src/dict.erl
@@ -387,7 +387,7 @@ merge(F, D1, D2) ->
update(K, fun (V1) -> F(K, V1, V2) end, V2, D)
end, D1, D2).
-
+
%% get_slot(Hashdb, Key) -> Slot.
%% Get the slot. First hash on the new range, if we hit a bucket
%% which has not been split use the unsplit buddy bucket.
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index 73b8da335a..ca6a4b5c58 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -912,7 +912,7 @@ type_test(binary) -> is_binary;
type_test(record) -> is_record;
type_test(Test) -> Test.
-
+
%% match(Pattern, Term, Bindings) ->
%% {match,NewBindings} | nomatch
%% or erlang:error({illegal_pattern, Pattern}).
@@ -1051,7 +1051,7 @@ match_list([], [], Bs, _BBs) ->
{match,Bs};
match_list(_, _, _Bs, _BBs) ->
nomatch.
-
+
%% new_bindings()
%% bindings(Bindings)
%% binding(Name, Bindings)
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index 4b654833ed..40ef6c8998 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -222,7 +222,7 @@ format_error(Atom) when is_atom(Atom) ->
format_error(Term) ->
lists:flatten(io_lib:format("~tp", [Term])).
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%% Useful definitions (also start of implementation).
@@ -412,7 +412,7 @@ split_filename([Comp|Rest], Prefix, Suffix, Len) ->
split_filename([], Prefix, Suffix, _) ->
{filename:join(Prefix),filename:join(Suffix)}.
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
%%% Retrieving files from a tape archive.
diff --git a/lib/stdlib/src/filelib.erl b/lib/stdlib/src/filelib.erl
index 9ef4954194..b8c0576e56 100644
--- a/lib/stdlib/src/filelib.erl
+++ b/lib/stdlib/src/filelib.erl
@@ -248,7 +248,7 @@ ensure_dir(F) ->
end
end.
-
+
%%%
%%% Pattern matching using a compiled wildcard.
%%%
@@ -360,7 +360,7 @@ do_alt([], _File) ->
do_list_dir(Dir, Mod) -> eval_list_dir(Dir, Mod).
-
+
%%% Compiling a wildcard.
%% Only for debugging.
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 7f65131f67..df68a37c06 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -393,7 +393,7 @@ decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) ->
end.
%%% ---------------------------------------------------
-%%% Send/recive functions
+%%% Send/receive functions
%%% ---------------------------------------------------
do_send(Dest, Msg) ->
case catch erlang:send(Dest, Msg, [noconnect]) of
diff --git a/lib/stdlib/src/io_lib.erl b/lib/stdlib/src/io_lib.erl
index 92a086b077..9e69601770 100644
--- a/lib/stdlib/src/io_lib.erl
+++ b/lib/stdlib/src/io_lib.erl
@@ -583,7 +583,7 @@ printable_unicode_list(_) -> false. %Everything else is false
nl() ->
"\n".
-
+
%%
%% Utilities for collecting characters in input files
%%
diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl
index b5577165f4..d6a9f4645d 100644
--- a/lib/stdlib/src/lists.erl
+++ b/lib/stdlib/src/lists.erl
@@ -630,7 +630,7 @@ flatlength([H|T], L) when is_list(H) ->
flatlength([_|T], L) ->
flatlength(T, L + 1);
flatlength([], L) -> L.
-
+
%% keymember(Key, Index, [Tuple]) Now a BIF!
%% keyfind(Key, Index, [Tuple]) A BIF!
%% keysearch(Key, Index, [Tuple]) Now a BIF!
@@ -1163,7 +1163,7 @@ rumerge(T1, []) ->
T1;
rumerge(T1, [H2 | T2]) ->
lists:reverse(rumerge2_1(T1, T2, [], H2), []).
-
+
%% all(Predicate, List)
%% any(Predicate, List)
%% map(Function, List)
diff --git a/lib/stdlib/src/math.erl b/lib/stdlib/src/math.erl
index c3fb684ec3..98a70b1644 100644
--- a/lib/stdlib/src/math.erl
+++ b/lib/stdlib/src/math.erl
@@ -51,9 +51,9 @@ asinh(_) ->
atan(_) ->
erlang:nif_error(undef).
--spec atan2(X, Y) -> float() when
- X :: number(),
- Y :: number().
+-spec atan2(Y, X) -> float() when
+ Y :: number(),
+ X :: number().
atan2(_, _) ->
erlang:nif_error(undef).
diff --git a/lib/stdlib/src/string.erl b/lib/stdlib/src/string.erl
index 4ed27ff4eb..d0bd0cb26e 100644
--- a/lib/stdlib/src/string.erl
+++ b/lib/stdlib/src/string.erl
@@ -257,7 +257,7 @@ chars(C, N, Tail) when N > 0 ->
chars(C, N-1, [C|Tail]);
chars(C, 0, Tail) when is_integer(C) ->
Tail.
-
+
%% Torbjörn's bit.
%%% COPIES %%%
@@ -461,7 +461,7 @@ sub_string(String, Start) -> substr(String, Start).
Stop :: pos_integer().
sub_string(String, Start, Stop) -> substr(String, Start, Stop - Start + 1).
-
+
%% ISO/IEC 8859-1 (latin1) letters are converted, others are ignored
%%
diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl
index 9b6f628aa9..00fb20489b 100644
--- a/lib/stdlib/test/binary_module_SUITE.erl
+++ b/lib/stdlib/test/binary_module_SUITE.erl
@@ -249,6 +249,10 @@ badargs(Config) when is_list(Config) ->
binary:matches(<<1,2,3>>,
{ac,ets:match_spec_compile([{'_',[],['$_']}])},
[{scope,{0,1}}])),
+ %% OTP-11350
+ badarg = ?MASK_ERROR(
+ binary:matches(<<"foo">>,
+ [<<>>, <<"f">>])),
?line badarg =
?MASK_ERROR(binary:longest_common_prefix(
[<<0:10000,1,2,4,1:3>>,
diff --git a/lib/stdlib/test/slave_SUITE.erl b/lib/stdlib/test/slave_SUITE.erl
index 37fc694083..1d6a3ac90d 100644
--- a/lib/stdlib/test/slave_SUITE.erl
+++ b/lib/stdlib/test/slave_SUITE.erl
@@ -230,7 +230,7 @@ rsh_test(ResultTo) ->
link(ResultTo),
?line {error, no_rsh} = slave:start(super, slave3).
-
+
%%% Utilities.
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index ba6f7cdb8a..90d3e69b0e 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 1.19.3
+STDLIB_VSN = 1.19.4
diff --git a/lib/test_server/src/ts.erl b/lib/test_server/src/ts.erl
index 8e71c69d35..189a71a8ce 100644
--- a/lib/test_server/src/ts.erl
+++ b/lib/test_server/src/ts.erl
@@ -622,7 +622,7 @@ run_test(File, Args, Options) ->
run_test(File, Args, Options, Vars) ->
ts_run:run(File, Args, Options, Vars).
-
+
%% This module provides some convenient shortcuts to running
%% the test server from within a started Erlang shell.
%% (This are here for backwards compatibility.)
diff --git a/lib/tools/emacs/erlang-eunit.el b/lib/tools/emacs/erlang-eunit.el
index f2c0db67dd..0adeff1a02 100644
--- a/lib/tools/emacs/erlang-eunit.el
+++ b/lib/tools/emacs/erlang-eunit.el
@@ -40,6 +40,10 @@ This is useful, reducing the save-compile-load-test cycle to one keychord.")
(defvar erlang-eunit-recent-info '((mode . nil) (module . nil) (test . nil) (cover . nil))
"Info about the most recent running of an EUnit test representation.")
+(defvar erlang-error-regexp-alist
+ '(("^\\([^:( \t\n]+\\)[:(][ \t]*\\([0-9]+\\)[:) \t]" . (1 2)))
+ "*Patterns for matching Erlang errors.")
+
;;;
;;; Switch between src/EUnit test buffers
;;;
diff --git a/lib/tools/emacs/erlang-start.el b/lib/tools/emacs/erlang-start.el
index e1dc86621e..76e0575e68 100644
--- a/lib/tools/emacs/erlang-start.el
+++ b/lib/tools/emacs/erlang-start.el
@@ -52,7 +52,7 @@
;;
;; To set the variable you can use the following command:
;; M-x set-variable RET debug-on-error RET t RET
-
+
;;; Code:
;;
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index 624042204c..c395d22356 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -697,6 +697,7 @@ resulting regexp is surrounded by \\_< and \\_>."
"char"
"cons"
"deep_string"
+ "iodata"
"iolist"
"maybe_improper_list"
"module"
@@ -708,6 +709,7 @@ resulting regexp is surrounded by \\_< and \\_>."
"nonempty_list"
"nonempty_improper_list"
"nonempty_maybe_improper_list"
+ "nonempty_string"
"no_return"
"pos_integer"
"string"
@@ -1025,7 +1027,7 @@ behaviour.")
(defvar erlang-mode-syntax-table nil
"Syntax table in use in Erlang-mode buffers.")
-
+
(defvar erlang-skel-file "erlang-skels"
"The type of erlang-skeletons that should be used, default
@@ -1272,7 +1274,7 @@ Unfortunately, XEmacs hasn't got support for a special Font
Lock syntax table. The effect is that `apply' in the atom
`foo_apply' will be highlighted as a bif.")
-
+
;;; Avoid errors while compiling this file.
;; `eval-when-compile' is not defined in Emacs 18. We define it as a
@@ -1321,7 +1323,7 @@ Lock syntax table. The effect is that `apply' in the atom
(require 'tempo)
(require 'compile))))
-
+
(defun erlang-version ()
"Return the current version of Erlang mode."
(interactive)
@@ -1516,7 +1518,7 @@ Other commands:
(set (make-local-variable 'outline-level) (lambda () 1))
(set (make-local-variable 'add-log-current-defun-function)
'erlang-current-defun))
-
+
(defun erlang-font-lock-init ()
"Initialize Font Lock for Erlang mode."
(or erlang-font-lock-syntax-table
@@ -1686,7 +1688,7 @@ plus variables, macros and records."
(font-lock-mode 1)
(funcall (symbol-function 'font-lock-fontify-buffer)))
-
+
(defun erlang-menu-init ()
"Init menus for Erlang mode.
@@ -1905,7 +1907,7 @@ Example:
The new menu is returned. No guarantee is given that the original
menu is left unchanged."
(delq entry items))
-
+
;; Man code:
(defun erlang-man-init ()
@@ -2228,7 +2230,7 @@ For example:
After installing the line, kill and restart Emacs, or restart Erlang
mode with the command `M-x erlang-mode RET'.")))
-
+
;; Skeleton code:
;; This code is based on the package `tempo' which is part of modern
@@ -2349,7 +2351,7 @@ The first character of DD is space if the value is less than 10."
(erlang-string-to-int (substring date 8 10))
(substring date 4 7)
(substring date -4))))
-
+
;; Indentation code:
(defun erlang-indent-command (&optional whole-exp)
@@ -3132,7 +3134,7 @@ commands."
(skip-chars-backward " \t")
(max (if (bolp) 0 (1+ (current-column)))
comment-column)))))
-
+
;;; Erlang movement commands
;; All commands below work as movement commands. I.e. if the point is
@@ -3336,7 +3338,7 @@ With negative argument go towards the beginning of the buffer."
(forward-sexp 1)
(buffer-substring start (point)))))
-
+
;;; Miscellaneous
(defun erlang-fill-paragraph (&optional justify)
@@ -3445,7 +3447,7 @@ at the end."
(error "Can't clone argument list"))
(insert args)
(set-mark p)))
-
+
;;; Information retrieval functions.
(defun erlang-buffer-substring (beg end)
@@ -3772,7 +3774,7 @@ exported function."
(store-match-data old-match-data)
(member (cons name arity) exports))))
-
+
;;; Check module name
;; The function `write-file', bound to C-x C-w, calls
@@ -3835,7 +3837,7 @@ This function is normally placed in the hook `local-write-file-hooks'."
;; Must return nil since it is added to `local-write-file-hook'.
nil)
-
+
;;; Electric functions.
(defun erlang-electric-semicolon (&optional arg)
@@ -4229,7 +4231,7 @@ This function is designed to be a member of a criteria list."
(erlang-skip-blank)
(looking-at "end[^_a-zA-Z0-9]")))
-
+
;; Erlang tags support which is aware of erlang modules.
;;
;; Not yet implemented under XEmacs. (Hint: The Emacs 19 etags
@@ -4539,7 +4541,7 @@ Tags can be given on the forms `tag', `module:', `module:tag'."
(or default (error "There is no default tag"))
spec)))))
-
+
;; Search tag functions which are aware of Erlang modules. The tactic
;; is to store new search functions into the local variables of the
;; TAGS buffers. The variables are restored directly after the
@@ -4715,7 +4717,7 @@ for a tag on the form `module:tag'."
(string= mod (erlang-get-module-from-file-name
(file-of-tag)))))))
-
+
;;; Tags completion, Emacs 19 `etags' specific.
;;;
;;; The basic idea is to create a second completion table `erlang-tags-
@@ -4834,7 +4836,7 @@ about Erlang modules."
;; Only the first one will be stored in the table.
(intern (concat module ":") table))))))
table))
-
+
;;;
;;; Prepare for other methods to run an Erlang slave process.
;;;
@@ -4916,7 +4918,7 @@ future, a new shell on an already running host will be started."
(call-interactively erlang-next-error-function))
-
+
;;;
;;; Erlang Shell Mode -- Major mode used for Erlang shells.
;;;
@@ -5052,7 +5054,7 @@ Selects Comint or Compilation mode command as appropriate."
(define-key map "\M-\C-m" 'compile-goto-error)
(unless inferior-erlang-use-cmm
(define-key map "\C-x`" 'erlang-next-error)))
-
+
;;;
;;; Inferior Erlang -- Run an Erlang shell as a subprocess.
;;;
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index bf21aa6b48..13d9aefb0c 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -255,16 +255,7 @@ compile_directory(Dir, Options) when is_list(Dir), is_list(Options) ->
end.
compile_modules(Files,Options) ->
- Options2 = lists:filter(fun(Option) ->
- case Option of
- {i, Dir} when is_list(Dir) -> true;
- {d, _Macro} -> true;
- {d, _Macro, _Value} -> true;
- export_all -> true;
- _ -> false
- end
- end,
- Options),
+ Options2 = filter_options(Options),
compile_modules(Files,Options2,[]).
compile_modules([File|Files], Options, Result) ->
@@ -273,6 +264,17 @@ compile_modules([File|Files], Options, Result) ->
compile_modules([],_Opts,Result) ->
reverse(Result).
+filter_options(Options) ->
+ lists:filter(fun(Option) ->
+ case Option of
+ {i, Dir} when is_list(Dir) -> true;
+ {d, _Macro} -> true;
+ {d, _Macro, _Value} -> true;
+ export_all -> true;
+ _ -> false
+ end
+ end,
+ Options).
%% compile_beam(ModFile) -> Result | {error,Reason}
%% ModFile - see compile/1
@@ -622,8 +624,9 @@ main_process_loop(State) ->
Compiled0 = State#main_state.compiled,
case get_beam_file(Module,BeamFile0,Compiled0) of
{ok,BeamFile} ->
+ UserOptions = get_compile_options(Module,BeamFile),
{Reply,Compiled} =
- case do_compile_beam(Module,BeamFile,[]) of
+ case do_compile_beam(Module,BeamFile,UserOptions) of
{ok, Module} ->
remote_load_compiled(State#main_state.nodes,
[{Module,BeamFile}]),
@@ -1421,12 +1424,23 @@ get_abstract_code(Module, Beam) ->
end.
get_source_info(Module, Beam) ->
+ Compile = get_compile_info(Module, Beam),
+ case lists:keyfind(source, 1, Compile) of
+ { source, _ } = Tuple -> [Tuple];
+ false -> []
+ end.
+
+get_compile_options(Module, Beam) ->
+ Compile = get_compile_info(Module, Beam),
+ case lists:keyfind(options, 1, Compile) of
+ {options, Options } -> filter_options(Options);
+ false -> []
+ end.
+
+get_compile_info(Module, Beam) ->
case beam_lib:chunks(Beam, [compile_info]) of
{ok, {Module, [{compile_info, Compile}]}} ->
- case lists:keyfind(source, 1, Compile) of
- { source, _ } = Tuple -> [Tuple];
- false -> []
- end;
+ Compile;
_ ->
[]
end.
diff --git a/lib/tools/src/tags.erl b/lib/tools/src/tags.erl
index 1c72ef8db5..e3cc51cdb2 100644
--- a/lib/tools/src/tags.erl
+++ b/lib/tools/src/tags.erl
@@ -292,7 +292,7 @@ word_char(C) when C >= $0, C =< $9 -> true;
word_char($_) -> true;
word_char(_) -> false.
-
+
%%% Output routines
%% Check the options `outfile' and `outdir'.
@@ -323,7 +323,7 @@ genout(Os, Name, Entries) ->
io:put_chars(Os, lists:reverse(Entries)).
-
+
%%% help routines
%% Flatten and reverse a nested list.
diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index c033be98a3..29b26c7a76 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -28,7 +28,7 @@
export_import/1,
otp_5031/1, eif/1, otp_5305/1, otp_5418/1, otp_6115/1, otp_7095/1,
otp_8188/1, otp_8270/1, otp_8273/1, otp_8340/1,
- otp_10979_hanging_node/1]).
+ otp_10979_hanging_node/1, compile_beam_opts/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -53,7 +53,7 @@ all() ->
dont_reconnect_after_stop, stop_node_after_disconnect,
export_import, otp_5031, eif, otp_5305, otp_5418,
otp_6115, otp_7095, otp_8188, otp_8270, otp_8273,
- otp_8340, otp_10979_hanging_node];
+ otp_8340, otp_10979_hanging_node, compile_beam_opts];
_pid ->
{skip,
"It looks like the test server is running "
@@ -1401,6 +1401,39 @@ otp_10979_hanging_node(_Config) ->
ok.
+compile_beam_opts(doc) ->
+ ["Take compiler options from beam in cover:compile_beam"];
+compile_beam_opts(suite) -> [];
+compile_beam_opts(Config) when is_list(Config) ->
+ {ok, Cwd} = file:get_cwd(),
+ ok = file:set_cwd(?config(priv_dir, Config)),
+ IncDir = filename:join(?config(data_dir, Config),
+ "included_functions"),
+ File = filename:join([?config(data_dir, Config), "otp_11439", "t.erl"]),
+ %% use all compiler options allowed by cover:filter_options
+ %% i and d don't make sense when compiling from beam though
+ {ok, t} =
+ compile:file(File, [{i, IncDir},
+ {d, 'BOOL'},
+ {d, 'MACRO', macro_defined},
+ export_all,
+ debug_info,
+ return_errors]),
+ Exports =
+ [{func1,0},
+ {macro, 0},
+ {exported,0},
+ {nonexported,0},
+ {module_info,0},
+ {module_info,1}],
+ Exports = t:module_info(exports),
+ {ok, t} = cover:compile_beam("t"),
+ Exports = t:module_info(exports),
+ cover:stop(),
+ ok = file:delete("t.beam"),
+ ok = file:set_cwd(Cwd),
+ ok.
+
%%--Auxiliary------------------------------------------------------------
analyse_expr(Expr, Config) ->
diff --git a/lib/tools/test/cover_SUITE_data/otp_11439/t.erl b/lib/tools/test/cover_SUITE_data/otp_11439/t.erl
new file mode 100644
index 0000000000..d1eb9f16ee
--- /dev/null
+++ b/lib/tools/test/cover_SUITE_data/otp_11439/t.erl
@@ -0,0 +1,11 @@
+-module(t).
+-export([exported/0]).
+-include("cover_inc.hrl").
+-ifdef(BOOL).
+macro() ->
+ ?MACRO.
+-endif.
+exported() ->
+ ok.
+nonexported() ->
+ ok.
diff --git a/lib/tools/test/eprof_SUITE_data/eed.erl b/lib/tools/test/eprof_SUITE_data/eed.erl
index 520c5f3dd1..5f2a21aa60 100644
--- a/lib/tools/test/eprof_SUITE_data/eed.erl
+++ b/lib/tools/test/eprof_SUITE_data/eed.erl
@@ -146,7 +146,7 @@ format_error({'EXIT', {Code, {Mod, Func, Args}}}) ->
[{Code, {Mod, Func, length(Args)}}]));
format_error(A) -> atom_to_list(A).
-
+
%%% Parsing commands.
@@ -327,7 +327,7 @@ when 0 =< Num1, Num1 =< Num2, Num2 =< State#state.lines ->
check_lines(_, _, _, _) ->
error(bad_linenum).
-
+
%%% Executing commands.
%% ($)= - print line number
@@ -657,7 +657,7 @@ undo_command(_, _, _) ->
write_command(_Cmd, [_First, _Last], _St) ->
error(not_implemented).
-
+
%%% Primitive buffer operations.
print_current(St) ->
@@ -717,7 +717,7 @@ wrap_next_line(State) when State#state.dot == State#state.lines ->
wrap_next_line(State) ->
next_line(State).
-
+
%%% Utilities.
get_pattern(End, Cmd, State) ->
diff --git a/lib/xmerl/src/xmerl.erl b/lib/xmerl/src/xmerl.erl
index 3249094e78..01af183eef 100644
--- a/lib/xmerl/src/xmerl.erl
+++ b/lib/xmerl/src/xmerl.erl
@@ -303,18 +303,17 @@ apply_tag_cb(Ms, F, Args) ->
apply_cb(Ms, F, '#element#', Args).
apply_cb(Ms, F, Df, Args) ->
- apply_cb(Ms, F, Df, Args, Ms).
-
-apply_cb([M|Ms], F, Df, Args, Ms0) ->
- case catch apply(M, F, Args) of
- {'EXIT', {undef,[{M,F,_,_}|_]}} ->
- apply_cb(Ms, F, Df, Args, Ms0);
- {'EXIT', Reason} ->
- exit(Reason);
- Res ->
- Res
+ apply_cb(Ms, F, Df, Args, length(Args)).
+
+apply_cb(Ms, F, Df, Args, A) ->
+ apply_cb(Ms, F, Df, Args, A, Ms).
+
+apply_cb([M|Ms], F, Df, Args, A, Ms0) ->
+ case erlang:function_exported(M, F, A) of
+ true -> apply(M, F, Args);
+ false -> apply_cb(Ms, F, Df, Args, A, Ms0)
end;
-apply_cb([], Df, Df, Args, _Ms0) ->
+apply_cb([], Df, Df, Args, A, _Ms0) ->
exit({unknown_tag, {Df, Args}});
-apply_cb([], F, Df, Args, Ms0) ->
- apply_cb(Ms0, Df, Df, [F|Args]).
+apply_cb([], F, Df, Args, A, Ms0) ->
+ apply_cb(Ms0, Df, Df, [F|Args], A+1).
diff --git a/lib/xmerl/src/xmerl_regexp.erl b/lib/xmerl/src/xmerl_regexp.erl
index 0c53e6f34a..9303bdb125 100644
--- a/lib/xmerl/src/xmerl_regexp.erl
+++ b/lib/xmerl/src/xmerl_regexp.erl
@@ -593,7 +593,7 @@ sub_first_match(S, {regexp,RE}) ->
nomatch -> nomatch
end.
-
+
%% This is the regular expression grammar used. It is equivalent to the
%% one used in AWK, except that we allow ^ $ to be used anywhere and fail
%% in the matching.
@@ -961,7 +961,7 @@ re_apply_or(never_match, R2) -> R2;
re_apply_or(R1, never_match) -> R1;
re_apply_or(nomatch, R2) -> R2;
re_apply_or(R1, nomatch) -> R1.
-
+
%% Record definitions for the NFA, DFA and compiler.
-record(nfa_state, {no,edges=[],accept=no}).
@@ -1026,7 +1026,7 @@ parse_reas([{RegExp,A}|REAs], S) ->
{error,E} -> {error,E}
end;
parse_reas([], Stack) -> {ok,reverse(Stack)}.
-
+
%% build_combined_nfa(RegExpActionList) -> {NFA,StartState}.
%% Build the combined NFA using Thompson's construction straight out
%% of the book. Build the separate NFAs in the same order as the
@@ -1147,7 +1147,7 @@ nfa_comp_class(Cc) ->
comp_crs([{C1,C2}|Crs], Last) ->
[{Last,C1-1}|comp_crs(Crs, C2+1)];
comp_crs([], Last) -> [{Last,maxchar}].
-
+
%% build_dfa(NFA, NfaStartState) -> {DFA,DfaStartState}.
%% Build a DFA from an NFA using "subset construction". The major
%% difference from the book is that we keep the marked and unmarked
@@ -1282,7 +1282,7 @@ accept([St|Sts], NFA) ->
#nfa_state{accept=no} -> accept(Sts, NFA)
end;
accept([], _NFA) -> no.
-
+
%% minimise_dfa(DFA, StartState, FirstState) -> {DFA,StartState}.
%% Minimise the DFA by removing equivalent states. We consider a
%% state if both the transitions and the their accept state is the
@@ -1331,7 +1331,7 @@ pack_dfa([D|DFA], NewN, Rs, PDFA) ->
pack_dfa(DFA, NewN+1, [{D#dfa_state.no,NewN}|Rs],
[D#dfa_state{no=NewN}|PDFA]);
pack_dfa([], _NewN, Rs, PDFA) -> {PDFA,Rs}.
-
+
%% comp_apply(String, StartPos, DFAReg) -> {match,RestPos,Rest} | nomatch.
%% Apply the DFA of a regular expression to a string. If
%% there is a match return the position of the remaining string and
diff --git a/lib/xmerl/src/xmerl_xpath.erl b/lib/xmerl/src/xmerl_xpath.erl
index b3301f2faf..be0e863ce4 100644
--- a/lib/xmerl/src/xmerl_xpath.erl
+++ b/lib/xmerl/src/xmerl_xpath.erl
@@ -713,10 +713,26 @@ node_test(_Test,
node_test({wildcard, _}, #xmlNode{type=ElAt}, _Context)
when ElAt==element; ElAt==attribute; ElAt==namespace ->
true;
-node_test({prefix_test, Prefix}, #xmlNode{node = N}, _Context) ->
+node_test({prefix_test, Prefix}, #xmlNode{node = N}, Context) ->
case N of
- #xmlElement{nsinfo = {Prefix, _}} -> true;
- #xmlAttribute{nsinfo = {Prefix, _}} -> true;
+ #xmlElement{nsinfo = {Prefix, _}} ->
+ true;
+ #xmlElement{expanded_name = {Uri, _}} ->
+ case expanded_name(Prefix, "_", Context) of
+ {Uri, _} ->
+ true;
+ _ ->
+ false
+ end;
+ #xmlAttribute{nsinfo = {Prefix, _}} ->
+ true;
+ #xmlAttribute{expanded_name = {Uri, _}} ->
+ case expanded_name(Prefix, "_", Context) of
+ {Uri, _} ->
+ true;
+ _ ->
+ false
+ end;
_ ->
false
end;
@@ -760,20 +776,21 @@ node_test({name, {_Tag, Prefix, Local}},
node_test({name, {Tag,_Prefix,_Local}},
#xmlNode{node = #xmlAttribute{name = Tag}}, _Context) ->
true;
-node_test({name, {_Tag, Prefix, Local}},
- #xmlNode{node = #xmlAttribute{expanded_name = {URI, Local},
- nsinfo = {_Prefix1, _},
- namespace = NS}}, _Context) ->
- NSNodes = NS#xmlNamespace.nodes,
- case lists:keysearch(Prefix, 1, NSNodes) of
- {value, {_, URI}} ->
- ?dbg("node_test(~, ~p) -> true.~n",
- [{_Tag, Prefix, Local}, write_node(NSNodes)]),
- true;
- false ->
- ?dbg("node_test(~, ~p) -> false.~n",
- [{_Tag, Prefix, Local}, write_node(NSNodes)]),
- false
+node_test({name, {Tag, Prefix, Local}},
+ #xmlNode{node = #xmlAttribute{name = Name,
+ expanded_name = EExpName
+ }}, Context) ->
+ case expanded_name(Prefix, Local, Context) of
+ [] ->
+ Res = (Tag == Name),
+ ?dbg("node_test(~p, ~p) -> ~p.~n",
+ [{Tag, Prefix, Local}, write_node(Name), Res]),
+ Res;
+ ExpName ->
+ Res = (ExpName == EExpName),
+ ?dbg("node_test(~p, ~p) -> ~p.~n",
+ [{Tag, Prefix, Local}, write_node(Name), Res]),
+ Res
end;
node_test({name, {_Tag, [], Local}},
#xmlNode{node = #xmlNsNode{prefix = Local}}, _Context) ->
diff --git a/lib/xmerl/test/xmerl_SUITE.erl b/lib/xmerl/test/xmerl_SUITE.erl
index e21355f877..8432e66a97 100644
--- a/lib/xmerl/test/xmerl_SUITE.erl
+++ b/lib/xmerl/test/xmerl_SUITE.erl
@@ -42,7 +42,7 @@
%%----------------------------------------------------------------------
all() ->
[{group, cpd_tests}, xpath_text1, xpath_main,
- xpath_abbreviated_syntax, xpath_functions,
+ xpath_abbreviated_syntax, xpath_functions, xpath_namespaces,
{group, misc}, {group, eventp_tests},
{group, ticket_tests}, {group, app_test},
{group, appup_test}].
@@ -205,6 +205,11 @@ xpath_functions(Config) ->
?line file:set_cwd(filename:join(?config(data_dir,Config),xpath)),
?line ok = xpath_abbrev:functions().
+xpath_namespaces(suite) -> [];
+xpath_namespaces(Config) ->
+ ?line file:set_cwd(filename:join(?config(data_dir,Config),xpath)),
+ ?line ok = xpath_abbrev:namespaces().
+
%%----------------------------------------------------------------------
latin1_alias(suite) -> [];
diff --git a/lib/xmerl/test/xmerl_SUITE_data/xpath/purchaseOrder.xml b/lib/xmerl/test/xmerl_SUITE_data/xpath/purchaseOrder.xml
index a5ae223d65..16090c3590 100644
--- a/lib/xmerl/test/xmerl_SUITE_data/xpath/purchaseOrder.xml
+++ b/lib/xmerl/test/xmerl_SUITE_data/xpath/purchaseOrder.xml
@@ -1,7 +1,8 @@
<?xml version="1.0"?>
<apo:purchaseOrder xmlns:apo="http://www.example.com/PO1"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
orderDate="1999-10-20">
- <billTo country="US">
+ <billTo country="US" xsi:type="apo:USAddress">
<name>Robert Smith</name>
<street>8 Oak Avenue</street>
<!-- etc. -->
@@ -10,7 +11,7 @@
<zip>95819</zip>
</billTo>
<apo:comment>Hurry, my lawn is going wild!</apo:comment>
- <shipTo country="US">
+ <shipTo country="US" xsi:type="apo:USAddress">
<name>Alice Smith</name>
<street>123 Maple Street</street>
<!-- etc. -->
diff --git a/lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl b/lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl
index 7b6f1e95b3..afd39b6598 100644
--- a/lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl
+++ b/lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl
@@ -8,6 +8,7 @@
-module(xpath_abbrev).
-export([test/0, check_node_set/2, ticket_6873/0, ticket_7496/0, functions/0]).
+-export([namespaces/0]).
-include("test_server.hrl").
-include_lib("xmerl/include/xmerl.hrl").
@@ -264,3 +265,33 @@ functions() ->
[city,city,comment]),
?line ok = Test(Doc2,"//*[starts-with(name(),'{http://www.example.com/PO1')]",
['apo:purchaseOrder','apo:comment']).
+
+
+namespaces() ->
+ {Doc,_} = xmerl_scan:file("purchaseOrder.xml", [{namespace_conformant, true}]),
+
+ %% Element name using regular namespace and context namespace declaration.
+ ?line [#xmlElement{nsinfo = {_, "purchaseOrder"}}] =
+ xmerl_xpath:string("/apo:purchaseOrder", Doc),
+ ?line [#xmlElement{nsinfo = {_, "purchaseOrder"}}] =
+ xmerl_xpath:string("/t:purchaseOrder", Doc, [{namespace, [{"t", "http://www.example.com/PO1"}]}]),
+
+ %% Wildcard element name using regular namespace and context namespace declaration.
+ ?line [#xmlElement{nsinfo = {_, "comment"}}] =
+ xmerl_xpath:string("./apo:*", Doc),
+ ?line [#xmlElement{nsinfo = {_, "comment"}}] =
+ xmerl_xpath:string("./t:*", Doc, [{namespace, [{"t", "http://www.example.com/PO1"}]}]),
+
+ %% Attribute name using regular namespace and context namespace declaration.
+ ?line [#xmlAttribute{nsinfo = {_, "type"}}, #xmlAttribute{nsinfo = {_, "type"}}] =
+ xmerl_xpath:string("//@xsi:type", Doc),
+ ?line [#xmlAttribute{nsinfo = {_, "type"}}, #xmlAttribute{nsinfo = {_, "type"}}] =
+ xmerl_xpath:string("//@t:type", Doc, [{namespace, [{"t", "http://www.w3.org/2001/XMLSchema-instance"}]}]),
+
+ %% Wildcard attribute name using regular namespace and context namespace declaration.
+ ?line [#xmlAttribute{nsinfo = {_, "type"}}, #xmlAttribute{nsinfo = {_, "type"}}] =
+ xmerl_xpath:string("//@xsi:*", Doc),
+ ?line [#xmlAttribute{nsinfo = {_, "type"}}, #xmlAttribute{nsinfo = {_, "type"}}] =
+ xmerl_xpath:string("//@t:*", Doc, [{namespace, [{"t", "http://www.w3.org/2001/XMLSchema-instance"}]}]),
+
+ ok.